git clone https://toreaurstad@bitbucket.org/toreaurstad/wcfaudiostreamdemo.git
git fetch && git checkout VideBase64String_05082018
The following method is added to our WCF service contract, note that now we leave the webHttpBinding and use a CustomBinding.
[OperationContract] byte[] GetVideoBytes(string videofile);There is no [WebGet] attribute this time, as noted we will not use WCF REST but SOAP instead. The web.config of the host website for the WCF services exposes this CustomBinding:
<system.serviceModel> <services> <service name="WcfStreamAudioDemo.Host.AudioService"> <endpoint behaviorConfiguration="RestBehaviorConfig" binding="webHttpBinding" bindingConfiguration="HttpStreaming" contract="WcfStreamAudioDemo.Common.IAudioServiceContract" /> </service> <service name="WcfStreamAudioDemo.Host.VideoService"> <endpoint behaviorConfiguration="RestBehaviorConfig" binding="webHttpBinding" bindingConfiguration="HttpStreaming" contract="WcfStreamAudioDemo.Common.IVideoServiceContract" /> <endpoint address="custom" binding="customBinding" bindingConfiguration="CustomBinding" contract="WcfStreamAudioDemo.Common.IVideoServiceContract" /> </service> </services> <bindings> <customBinding> <binding name="CustomBinding"> <binaryMessageEncoding> <readerQuotas maxArrayLength="100000000" maxStringContentLength="100000000"/> </binaryMessageEncoding> <httpTransport /> </binding> </customBinding> <webHttpBinding> <binding name="HttpStreaming" transferMode="Streamed" maxReceivedMessageSize="1000000000" maxBufferPoolSize="100000000"> <readerQuotas maxArrayLength="100000000" maxStringContentLength="100000000"/> </binding> </webHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior> <!-- To avoid disclosing metadata information, set the values below to false before deployment --> <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> <endpointBehaviors> <behavior name="RestBehaviorConfig"> <webHttp /> </behavior> </endpointBehaviors> </behaviors> <protocolMapping> <add binding="basicHttpsBinding" scheme="https" /> </protocolMapping> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" /> </system.serviceModel>Note that the custom binding allows us to set up a binaryMessageEncoding. The next step is to go to the client project and add a service reference to the host project containing the WCF service. The app.config file is then updated, relevant parts shown here:
<system.webServer> <directoryBrowse enabled="true" /> <security> <requestFiltering> <requestLimits maxAllowedContentLength="1073741824" /> </requestFiltering> </security> <staticContent> <mimeMap fileExtension=".mp4" mimeType="video/mp4" /> </staticContent> </system.webServer> <system.serviceModel> <bindings> <customBinding> <binding name="CustomBinding"> <binaryMessageEncoding> <readerQuotas maxArrayLength="100000000" maxStringContentLength="100000000" /> </binaryMessageEncoding> <httpTransport maxReceivedMessageSize="100000000" /> </binding> </customBinding> </bindings> <client> <endpoint address="http://he139920.helsemn.no/WcfStreamAudioDemo.Host/VideoService.svc/custom" contract="VideoService.IVideoServiceContract" binding="customBinding" bindingConfiguration="CustomBinding" /> </client> </system.serviceModel>Note the changes of setting up a MIME map for .mp4 files and setting up requestlimits. I will explain this soon. The client script now actually consists both of a server side script run in ASP.NET that sets up the video control in two ways. One way is to construct a HTML5 Data Url. This clearly was demanding for the browser to cope with and is not recommended. The video is actually embed on the page as a base64 encoded string! For a small video such as our video, it is actually possible still. It is of course fascinating that we can embed an entire video on our ASPX web page just as a Base64 encoded string, like it or not. The way to do this anyways is like this:
<script runat="server"> private void btnInvokeWcfService_OnClick(object sender, EventArgs e) { using (var proxy = new VideoServiceContractClient()) { byte[] payload = proxy.GetVideoBytes("sintel_trailer-480p"); SetVideoSourceToHtmlDataUri(payload); } } private void SetVideoSourceToHtmlDataUri(byte[] payload) { //Set a base64 Html data uri videoCtrlFedByByteArrayThroughProxy.Attributes["type"] = "video/mp4"; string base64String = Convert.ToBase64String(payload); videoCtrlFedByByteArrayThroughProxy.Attributes["src"] = "data:video/mp4;base64," + base64String; } </script>The following image shows how this actually works! Of course, this gives rendering and performance issues, as the web page now got very large content - the entire video is embedded into the page! Another way is to write the byte array to a temporary file on the server, and set the src attribute to this temporary file.
<script runat="server"> private void btnInvokeWcfService_OnClick(object sender, EventArgs e) { using (var proxy = new VideoServiceContractClient()) { byte[] payload = proxy.GetVideoBytes("sintel_trailer-480p"); SetVideoSourceToTempFile(payload); } } private void SetVideoSourceToTempFile(byte[] payload) { //write to a temp file string tempfile = Path.GetRandomFileName() + ".mp4"; string tempfilePathForWebServer = HttpContext.Current.Server.MapPath("media/") + tempfile; File.WriteAllBytes(tempfilePathForWebServer, payload); videoCtrlFedByByteArrayThroughProxy.Attributes["src"] = "media/" + tempfile; } </script>Note that in these two samples, I have adjusted the HTML5 video control to be accessible to ASP.NET like this:
<asp:Button runat="server" ID="btnInvokeWcfService" Text="Load Video" OnClick="btnInvokeWcfService_OnClick"/> <video id="videoCtrlFedByByteArrayThroughProxy" type="video/mp4" runat="server" controls width="320" height="240"> <p>Your browser doesn't support HTML5 video. Here is a <a href="http://wcfaudiodemohost.azurewebsites.net/VideoService.svc/mediabytes/sintel_trailer-480p">link to the video</a> instead.</p> </video>This method of retrieving video from WCF is the quickest way, it only fetches the original byte array data and it loads quickly. An adjusted version would not write to a file directly accessible on the web server, but use for example IsolatedStorage instead. I will look into that in the future. Hope you found this article interesting. CustomBindings in WCF gives you a lot of flexibility!
No comments:
Post a Comment