Tuesday, March 31, 2015

HttpResponseMessage PDF file is downloading as HTML using StreamContent

If you have a PDF file which is accessed using StreamContent on HttpResponseMessage it is important to set MediaTypeHeaderValue to the correct value for PDF documents. Otherwise the browser will assume it is HTML begin accessed. This can be set with the following line of code:
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

Friday, March 20, 2015

CSRF in AngularJS/Web API on Web Forms (ng-resource)

I came across an interesting site configuration where there was need of anti forgery tokens (due to Cross-Site Request Forgery exploits), however it was a web forms implementation and AngularJS was making Web API calls via $resource (both GET and POST).
app.factory('LoginProvider', function ($resource) {
 return $resource('/api/login/:id', { id: '@id' },
  { 'save': { method: 'POST', headers: { 'X-XSRF-Token': angular.element('input[name="__RequestVerificationToken"]').attr('value') } } });

app.factory('OtherProvider', function ($resource) {
 return $resource('/api/OtherProvider/:id', { id: '@id' },
  {'get': { method: 'GET', headers: { 'X-XSRF-Token': angular.element('input[name="__RequestVerificationToken"]').attr('value') } }});
using System;
using System.Linq;
using System.Net.Http;
using System.Web.Helpers;
using System.Web.Http.Filters;

namespace Web.Common.AntiForgery
    public sealed class AntiForgeryTokenAttribute : ActionFilterAttribute
        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
            if (actionContext == null)
                throw new ArgumentNullException("actionContext");
            var headers = actionContext.Request.Headers;
            var cookie = headers
                .Select(c => c[AntiForgeryConfig.CookieName])
            var tokenFromHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
            System.Web.Helpers.AntiForgery.Validate(cookie != null ? cookie.Value : null, tokenFromHeader);

<%# AntiForgery.GetHtml() %>
namespace Web.Services
    public class LoginController : ApiController
        public IHttpActionResult Post([FromBody]LoginRequestModel request)
            var response = new LoginResponseModel();
            // Business Logic
            return Ok(response);
The code on the master page (or can be placed on the form) is what puts the hidden field containing the token on the page. The ActionFilterAttribute is defined as "AntiForgeryTokenAttribute", but on the Web API side the Attribute is dropped and it is simply "[AntiForgeryToken]".

On the AngularJS side, the $resource POST request adds in the header "X-XSRF-Token", which connects with the hidden field on the master page (or layout). I place it here instead of in the form in case there are multiple forms on the same page that require anti forgery tokens.

Friday, March 13, 2015

AngularJS output trusted HTML to view using Strict Contextual Escaping

With AngularJS if you simply output a string of HTML to the page, it will be output as straight text rather than output as HTML. Using the ng-bind-html tag the HTML can then be output to the view/page as follows:
<div ng-bind-html="MyHtmlVar"></div>
However as of AngularJS version 1.3 the HTML is not considered trusted to be output to the page and the following error would occur "Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context.". In the controller you would need to use $sce.trustAsHtml() to set the HTML as safe.
$scope.MyHtmlVar = $sce.trustAsHtml(inputString)
Also don't forget to reference $sce (Strict Contextual Escaping service) in the controller definition.

In the case of user entered HTML (such as commenting) it is recommended that you sanitize the HTML using a library before setting it to trusted.

You can also disable the need for SCE completely (meaning ng-bind-html will work without errors), however this would only be recommended for existing projects that would require significant re-factoring. For new projects there is very little code overhead in using SCE and the security benefits are worth the effort.

Wednesday, March 11, 2015

Task parallelism in C# run multiple methods in parallel asynchronously

Version 4 of the .NET framework introduced the task parallel library, which has a Task (being an asynchronous operation). Task parallelism basically means multiple independent tasks (operations) running at the same time. The main benefit of using Task parallelism is a more efficient use of system resources and the extra methods available around tasks (such as cancellations and even scheduling).

One possible use of tasks is where you need to run a bulk action on a number of objects, for example changing a detail on each object. Looping through each change would mean that the previous operation must complete before calling the next, and where a service call is made to make the change, run time can add up. The following example shows how you can build an array of Tasks (each a separate operation call) and then run them all at once asynchronously.
var addressChanges = request.AddressChangesRequired;

if (addressChanges.Any())
    var tasks = new List<Task>();

    foreach (var addressChange in addressChanges)
        var memberNumber = addressChange.MemberNumber;
 var address = addressChange.Address;
        tasks.Add(Task.Run(() => EditMemberAddress(new EditMemberAddressRequest
            Address = address,
            MemberNumber = memberNumber

The reason member number and address are declared as variables instead of referencing the object in the for loop is that when the Tasks go to run, they will all reference the same object (the last one in the for loop).

EditMemberAddress is the operation which is begin called and the request object is what has been passed into the service (and is an array of address changes required).

Tuesday, March 3, 2015

AutoMapper to map from single object to array

When the destination of AutoMapper is an array and the input is a single object, errors can be thrown, particularity by mapping unit tests. There is a simple fix to allow the mapping to work as exptected:
.ForMember(dest => dest.PhoneNumbers, expression => expression.MapFrom(x => new[]{ x.PhoneNumber }))