Web API Audio Streaming

I had a requirement to push streamed audio from Microsoft Speak API to a Web API consumer and had to cobble together some samples from a few different sources in order to succeed.  Since I didn’t find one ‘silver bullet’ source for this, I thought I would share mine.  The MS Speak API code can be found here using the local SoundPlayer media class to output the sound to your local machine.  This article gave me most of what I needed for pushing the MS stream out through my Web API.   The final solution is presented below…

First, it was essential to understand the PushStreamContent class and it’s ability to accept an async method with a content type and asynchronously output this stream to the caller, in this case, the content of an HttpResponseMessage.

The API Controller would contain the following:

public HttpResponseMessage Get()
{
  var audio = new AudioStream(parameter); 
  var response = Request.CreateResponse(); 
  response.Content = new PushStreamContent(audio.WriteToStream, new         MediaTypeHeaderValue("audio/wav")); 
  return response;
}

The bold method call above is what the PushStreamContent class uses to manage the asynchronous behavior.

Below is the method that performs the streaming:

public class AudioStream
{
  //constructor where you can pass parameters into
  public AudioStream()
  {
 
  }

 public async void WriteToStream(Stream outputStream, HttpContent        content, TransportContext context)
 {
    try
    {
       var buffer = new byte[65536];
       WebResponse response = getTTSStream();
       using (Stream stream = response.GetResponseStream())
       { 
          int count = 0;
          do
          {
             count = stream.Read(buffer, 0, 65536);
             await outputStream.WriteAsync(buffer, 0, count);
          } while (stream.CanRead && count > 0);
       }
    }
    catch (HttpException ex)
    {
       return;
    }
    finally
    {
       outputStream.Close();
    }
  }
}

The outputStream, containing a buffered subset of the stream, gets returned to the caller on an await.  When the task completes, it invokes its continuation, and execution of the async method resumes where it left off (as per MS), retrieving the next buffered subset of the stream.

Angular and ServiceStack Session Management

This article is meant to consolidate the components necessary for session management between Angular and ServiceStack.  I’ve found many articles discussing one or the other, but not many describing the complete picture.  For web applications with authentication, you will typically need a means of managing the user session on the client.  There are a few facets to this no matter the web client or server:

  1. Web Servers provide Session management with an expiration
  2. Web Sites should have a idle timeout
  3. Web Sites should communicate with server code to either keep the server session alive or expire it.

Different technologies accomplish this in different ways.  On the client, some kind of scripting language, such as javascript, is used to set a timeout on a newly requested page.  When the timeout is reached, the user is redirected to a logout page that makes the call to the server thereby killing the session.  On the server, web servers such as IIS and Apache start the session at the user’s first request, slides  it as more requests come in, and terminates it after the session timeout has been reached.

Sliding the expiration simply means that it pushes the session timeout 15-20 more minutes or so.  The session expiration needs to be stored in a configuration file in both the client and the server.  Unfortunately, sometimes this configuration is not shared between the two.  For Angular, I store the session timeout (e.g. 20 minutes) in config.js and load it into the ngIdle configuration which I will be discussing later.  In ServiceStack, I use an AppSetting variable in my web.config which I then store in a global or cached object when the user authenticates.  That way, I can inject this object into any part of ServiceStack I wish.

No matter the technology, #2 above must still be handled with scripting to count down the seconds that a page has been open or idle.  For Angular, I used ngIdle to accomplish most of my needs.

angular.module('app')
   .service('sessionService', ['$rootScope', 'logger', sessionServic            e]);
   function sessionService($rootScope, logger) {
          var scope = $rootScope;
          var started = false;
          scope.$on('$idleStart', function () {
          });
          scope.$on('$idleEnd', function () {
          });
          scope.start = function () {
                 $idle.watch();
                 started = true;
          };
         scope.$on('$idleTimeout', function () {
                  started = false;
                  logger.logWarning('Your screen was idle', null,                         'sessionService', true);
                  scope.stop;
                  logout();  //resets any config vars, calls service                             //stack to logout session and redirects                             //to login page
          });
          scope.stop = function () {
                 $idle.unwatch();
                 started = false;
          };
          return {
                 getScope: function () {
                         return scope;
                 },
                setScope: function (value) {
                         scope = value;
                         scope.start;
                }
         };
}

In my app.js I have:

$idle.watch();

In my config.js I have:

app.config(['$keepaliveProvider', '$idleProvider', function ($keepaliveProvider, $idleProvider) {
 var secondsTimeout = config.sessionExpiration * 60;
 $idleProvider.idle(secondsTimeout);
 $idleProvider.timeout(secondsTimeout);
 
 }]);

For #3 above,  keeping the session alive is accomplished for each service call.  I used a simple Request Filter to reset the session’s expiration then applied the attribute to the services within ServiceStack.   I found an implementation of the original code here.  In my version, I actually store a session expiration web.config value in my customUserSession object so that I can use it when necessary.  I then inject the customUserSession into the request filter which allows me to resave my customUserSession to cache. I’m sure it’s also possible to slide the expiration in a global request filter.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
 public class SlideExpirationAttribute : RequestFilterAttribute
 {
 public TimeSpan? Expiry { get; set; }
 private int sessionExpiration;
 public ICacheClient memoryCacheClient { get; set; }
 public SlideExpirationAttribute(int expiry)
 {
 
     public override void Execute(IRequest req, IResponse res,               object requestDto)
     {
         try
         {
             IHttpRequest httpReq = (IHttpRequest)req;
             IHttpResponse httpRes = (IHttpResponse)res;

             var session = httpReq.GetSession();
             memoryCacheClient = HostContext.TryResolve<ICacheClient             >();
             CustomUserSession customSession = memoryCacheClient.Get             <CustomUserSession>(session.Id);

             memoryCacheClient.Set<CustomUserSession>(customSession.             Id, customSession, customSession.SessionExpiration);
             if (session != null) httpReq.SaveSession(session, custo             mSession.SessionExpiration);
          }
          catch
          {

          }
 }

Then add the attribute on top of your ServiceStack service.

[SlideExpiration]
public object myService(MyRequest request)

In conclusion, I wanted to demonstrate the entire picture between client and server. With a few libraries and code snippets it’s fairly easy to build a well-structured session management architecture for Angular and ServiceStack.  If anything, I hope this post provides the reader more of the pieces they need to get started.

 

Angular Anti-forgery Management via ServiceStack

One aspect of securing any website is to guard against a cross-site request forgery (XSRF) attack. You can get a decent sense of what this attack is here, but it essentially allows a hacker to use an unexpired session cookie from site A, if the user browses to a hacker’s site B, to post his own data to site A.  This is a critical attack to guard against if you are a financial or government institution.

ASP.net has a convenient mechanism for managing this between the client and server namely using an ValidateAntiForgeryToken attribute in the server code and a hidden form field ‘__RequestVerificationToken’  on the client.  Angular had no such built in method for handling this and we were using ServiceStack as our back-end so I really had to understand this simple, but effective, hand-shaking technique.

No matter what type of server you are using to prevent XSRF, it will provide a mechanism to create a client HTTP-only cookie to be used to validate your anti-forgery token with.

The following steps illustrate how to perform this between Angular and ServiceStack.  I only wanted to highlight the most important steps here as this be done in varying ways:

1.  From the server, use ServiceStack’s built in HtmlHelper class to create your token and return the value to the client:

//Set Antiforgery Cookie name for future use
AntiForgeryConfig.CookieName = ConfigurationManager.AppSettings["xsrfCookieName"].ToString();
//This reads value from the httpCookies web.config element
 MvcHtmlString antiForgeryToken = helper.AntiForgeryToken();
//Do some parsing to get the final token value...
return token;

2.  From the client-side, store the token in config.js to reuse for all future non-GET calls.

3.  From the client-side, you can set global HTTP verb headers.  This by-passes the need to include a hidden form field in every form.

$http.default.headers.post = { "XSRF-TOKEN":config.antiforgeryToken}

4.  On the server, you will need a request filter to validate your service calls.  You can find a version of one here.  I modified mine to check a header value.

IEnumerable<string> xRequestedWithHeaders = request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault();

Once I get the token value from the header, I validate it with the cookie using the AntiXsrf (Antiforgery) class:

try{
   AntiForgeryConfig.CookieName = ConfigurationManager.AppSettings["   xsrfCookieName"].ToString();
   var cookie = request.Cookies.FirstOrDefault(c => c.Value.Name.Con   tains(AntiForgeryConfig.CookieName));
   AntiForgery.Validate(cookie.Value.Value, headerValue);
 }
 catch (Exception ex)
 {
   res.StatusCode = 403;
   res.StatusDescription = ex.Message;
   //throw new Exception(ex.Message.ToString()); 
   res.EndHttpHandlerRequest();//new System.Web.Mvc.HttpAntiForgeryE   xception
 
 }

5.  Finally, on the server, you’ll want to attach this to the Global Request filter in ServiceStack or set this attribute on any Post, Put, etc call you wish to secure.

[ValidateHttpAntiForgeryToken]
public object Post(MyPostRequest request)
{

}