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