Streaming Media Content Over WCF RESTful Service

|

WCF RESTful service API enables you to serve POX type of content over the http transport, and its default content-type header is application/xml if you use DataContractSerializer and application/json if you use DataContractJsonSerializer. If you need to serve up other contents for instance video/audio content, you need to explicitly control the content-type header, this could be achieved again by writing custom message formatter as demonstrated in the previous post, here is the code:

public class ContentTypeMessageFormatter : IDispatchMessageFormatter
{
    private IDispatchMessageFormatter formatter;
    private String contentType;
    public ContentTypeMessageFormatter(IDispatchMessageFormatter formatter, String contentType)
    {
        this.formatter = formatter;
        this.contentType = contentType;
    }

    public void DeserializeRequest(Message message, object[] parameters)
    {
        formatter.DeserializeRequest(message, parameters);
    }

    public Message SerializeReply(MessageVersion messageVersion, Object[] parameters, Object result)
    {
        if (!String.IsNullOrEmpty(contentType))
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
        }
        return formatter.SerializeReply(messageVersion, parameters, result);
    }
}

public class ContentTypeAttribute : Attribute, IOperationBehavior
{
    public ContentTypeAttribute(String contentType)
    {
        this.ContentType = contentType;
    }

    public String ContentType
    {
        get;
        set;
    }

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new ContentTypeMessageFormatter(dispatchOperation.Formatter, ContentType);
    }

    public void Validate(OperationDescription operationDescription)
    {
    }
}

Then you could directly specify the ContentTypeAttribute at the service operation level, the following service could stream WMV video content over http by turning on the streamed transfer mode of WCF:

[ServiceContract]
public interface IMediaService
{
    [OperationContract]
    [ContentType("audio/x-ms-wmv")]
    [WebGet(UriTemplate = "media/{name}")]
    Stream GetMedia(String name);
}

[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
public class MediaService : IMediaService
{
    public Stream GetMedia(String name)
    {
        var dir = HttpContext.Current.Server.MapPath("~");
        var file = String.Format("{0}.wmv", name);
        var filePath = Path.Combine(dir, file);
        return File.OpenRead(filePath);
    }
}

You turn on streaming in WCF, you need to configure the service as follows:

<system.serviceModel>
  <
serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  <
services>
    <
service
     behaviorConfiguration="serviceBehavior"
     name="CustomContentTypeInRESTDemo.MediaService">
      <
endpoint
       behaviorConfiguration="RestBehaviorConfig"
       binding="webHttpBinding"
       bindingConfiguration="HttpStreaming"
       contract="CustomContentTypeInRESTDemo.IMediaService"/>
    </
service>
  </
services>
  <
bindings>
    <
webHttpBinding>
      <
binding name="HttpStreaming" maxReceivedMessageSize="67108864" transferMode="Streamed"/>
    </
webHttpBinding>
  </
bindings>
  <
behaviors>
    <
endpointBehaviors>
      <
behavior name="RestBehaviorConfig">
        <
webHttp/>
      </
behavior>
    </
endpointBehaviors>
  </
behaviors>
</
system.serviceModel>

Streaming audio/video content using RESTful service could be pretty useful, in particular if you need to use WPF’s MediaElement to playback content provided by your service, since MediaElement only allows you to specify a Uri of the media file, the DirectShow has build-in source filter to feed video/audio bits from HTTP transport or local file system, but doesn’t provide a built-in source filter to read media bits from arbitrary stream.

In WPF, you could directly have MediaElement’s Source property pointing to the templated REST Uri:

<MediaElement Source="http://localhost:8080/MediaService.svc/media/testVideo"/>

Actually, if you need VCR type of control over the streamed media content, then you need native protocol level support such as RTSP. Windows Media Services is Microsoft’s server implementation of RTSP protocol, and is available in Windows Server 2003 and Windows Server 2008. This link illustrates how to configure WMS in Windows Server 2003.

1 comments:

Anonymous said...

I get an error.
The server encountered an error processing the request. See server logs for more details.