Saturday 23 May 2015

Logging WPF binding errors to the Event Log and testing this

WPF developers know that WPF binding errors are elusive. The XAML code is populated with binding expressions that are not strongly bound, but written as text. Whereas Razor MVC views support strongly bound MVC views, WPF developers must keep a keen eye to the debugger output view as their application run to spot WPF binding errors. These binding errors are not thrown and hard to track down. In addition, if there is present one WPF binding error per item in an items control, the WPF application will quickly behave slow, indicating a possible WPF binding error or several as is often the case. It is possible to track binding errors to the Event Log. In this article I will present code I use to track or trace binding errors to the Event Log and a NUnit integration test that actually test out the binding trace listener. Let's first review the code for the WPF binding error trace listener:


 public class BindingErrorTraceListener : DefaultTraceListener
    {
        private static BindingErrorTraceListener _Listener;

        public static void SetTrace()
        { SetTrace(SourceLevels.Error, TraceOptions.None); }

        public static void SetTrace(SourceLevels level, TraceOptions options)
        {
            if (_Listener == null)
            {
                _Listener = new BindingErrorTraceListener();
                PresentationTraceSources.DataBindingSource.Listeners.Add(_Listener);
            }

            _Listener.TraceOutputOptions = options;
            PresentationTraceSources.DataBindingSource.Switch.Level = level;
        }

        public static void CloseTrace()
        {
            if (_Listener == null)
            { return; }

            _Listener.Flush();
            _Listener.Close();
            PresentationTraceSources.DataBindingSource.Listeners.Remove(_Listener);
            _Listener = null;
        }



        private StringBuilder _Message = new StringBuilder();

        private BindingErrorTraceListener()
        { }

        public override void Write(string message)
        { _Message.Append(message); }

        public override void WriteLine(string message)
        {
            _Message.Append(message);

            var final = "WPF DataBinding Error detected: " +
                Environment.NewLine + _Message.ToString();
            _Message.Length = 0;

            var logger = new EventLogProvider();
            if (logger != null)
                logger.Log("OpPlan 4.x Client WPF Data Binding Error found: " + final, Microsoft.Practices.Prism.Logging.Category.Warn,
                     Microsoft.Practices.Prism.Logging.Priority.Medium);
        }
    }

The class above BindingErrorTraceListener inherits from DefaultTraceListener in the System.Diagnostics namespace. It is adding itself to the PresentationSources.DataBindingSource.Listeners property collection, this is also in the System.Diagnostics namespace. The class uses another class called EventLogProvider, which implements ILoggerFacade (used in PRISM applications), which will be presented below. Please note that the DefaultTraceListener is already added to this collection. The following code will add the implementation above to the listener collection in the OnStartup method of the WPF application class codebehind - App.xaml.cs:

public partial class App {

.. 


 protected override void OnStartup(StartupEventArgs e) {
  
  if (Debugger.IsAttached){
   BindingErrorTraceListener.SetTrace();   
  }

 }

}

Note that the listener is added to the listener collection if a debugger is attached. WPF binding errors should be detected by the developer and resolved before software is published and/or shipped to the customers. The EventLogProvider class is simply a wrapper to the EventLog class in System.Diagnostics namespace.

using System.Configuration;
using System.Diagnostics;
using Hemit.Diagnostics;
using Microsoft.Practices.Prism.Logging;

namespace Hemit.OpPlan.Client.Infrastructure
{
    //[Export(typeof(ILoggerFacade))]
    //[PartCreationPolicy(CreationPolicy.Shared)]
    public class EventLogProvider : ILoggerFacade
    {
        public const int MaxLogMessageLength = 32765;
        public string EventLogSourceName { get; set; }


        public EventLogProvider()
        {
            EventLogSourceName = ConfigurationManager.AppSettings[Constants.EventLogSourceNameMefKey];
        }

        private void WriteEntry(string message, Category category, Priority priority)
        {
            int eventID = 0;

            System.Diagnostics.EventLog.WriteEntry(EventLogSourceName, message, GetEventLogEntryType(category), eventID, GetPriorityId(priority));
        }

        private static EventLogEntryType GetEventLogEntryType(Category category)
        {
            switch (category)
            {
                case Category.Debug:
                    return EventLogEntryType.Information;
                case Category.Exception:
                    return EventLogEntryType.Error;
                case Category.Info:
                    return EventLogEntryType.Information;
                case Category.Warn:
                    return EventLogEntryType.Warning;
                default:
                    return EventLogEntryType.Error;
            }
        }

        private static short GetPriorityId(Priority priority)
        {
            switch (priority)
            {
                case Priority.None:
                    return 0;
                case Priority.High:
                    return 1;
                case Priority.Medium:
                    return 2;
                case Priority.Low:
                    return 3;
                default:
                    return 0;
            }
        }

        #region ILoggerFacade Members

        public void Log(string message, Category category, Priority priority)
        {
            WriteEntry(message, category, priority);
        }

        #endregion
    }
}

It is also nice to make an integration test to actually test that the WPF binding error trace listener actually works. I only use the integration to simulate a WPF binding error, but one can extend the EventLogProvider class to retrieve an Event Log Item that matches some certain text


    [TestFixture]
    public class BindingErrorTraceListenerUtilityTest
    {

        [Test]
        [RequiresSTA]
        public void Wpf_BindingError_Causes_Logging_Through_BindingTraceErrorListener()
        {
             
            BindingErrorTraceListener.SetTrace();
           
            var sausages = new[]
            {
                new {Product = "Hot dog", Cost = 25},
                new {Product = "Wiener", Cost = 42},
                new {Product = "Bratwurst", Cost = 53},
                new {Product = "Trailer grill shrimp salad with all extras deluxe edition", Cost = 112 }
            };

            string tbName = "tbGoof";
            var sausageBooth = new ListBox();
            var vt = new FrameworkElementFactory(typeof(TextBlock));
            vt.Name = tbName;
            vt.SetBinding(TextBlock.TextProperty, new Binding("Costt")); //Her setter man en WPF binding error 

            var groupBox = new GroupBox {DataContext = sausages[3]};
            groupBox.SetBinding(HeaderedContentControl.HeaderProperty, "Costt");

            var bindingExpressionGroupHeader = BindingOperations.GetBindingExpressionBase(groupBox, HeaderedContentControl.HeaderProperty);
            if (bindingExpressionGroupHeader != null)
                bindingExpressionGroupHeader.UpdateTarget();

            sausageBooth.ItemTemplate = new DataTemplate()
            {
                VisualTree = vt
            };
            sausageBooth.ItemsSource = sausages;

            sausageBooth.UpdateLayout();

            IItemContainerGenerator generator = sausageBooth.ItemContainerGenerator;
            GeneratorPosition position = generator.GeneratorPositionFromIndex(0);
            using (generator.StartAt(position, GeneratorDirection.Forward, true))
            {
                foreach (object o in sausageBooth.Items)
                {
                    DependencyObject dp = generator.GenerateNext();
                    generator.PrepareItemContainer(dp);
                }
            }

            ListBoxItem firstComboBoxItem = (ListBoxItem) sausageBooth.ItemContainerGenerator.ContainerFromIndex(0);
            Assert.IsNotNull(firstComboBoxItem);
            firstComboBoxItem.ContentTemplate.Seal();
            var dt = firstComboBoxItem.ContentTemplate.LoadContent();
            Assert.IsNotNull(dt);
            var textblock = dt as TextBlock;
            Assert.IsNotNull(textblock);
            textblock.SetBinding(TextBlock.TextProperty, new Binding("Costt"));
            var bindingTextBlock = BindingOperations.GetBindingExpressionBase(textblock, TextBlock.TextProperty);
            Assert.IsNotNull(bindingTextBlock);
            bindingTextBlock.UpdateTarget();

        }


Note that the integration above will run through and not assert anything at the end if the Event Log item was really added, but it will be easy to inspect the Event Log using the eventvwr command and check that the WPF binding error was really added. The BindingErrorTraceListener class adds wpf binding errors as warnings in the event log, as the following screen shot display:

Wednesday 8 April 2015

Configuring CORS in MVC Web Api 2

This article will describe how developers can handle the restrictions of the Same-Origin Policy that exists in all browsers today by relaxing these restrictions using CORS, Cross-origin resource sharing. Developers that have worked some with Javascript and Ajax calls, for example using jQuery, know about the limitations that are imposed on browsers for scripts to abide the "same-origin policy". If a script written in Javascript tries to access a remote resource on another host, or even another website and/or port on the same machine, chances are high that the Ajax call will although executed, not be returned to the caller (calling script). Typically if a developer checks the Developer Tools in a browser (usually F12), the following error pops up:

XMLHttpRequest cannot load http://localhost:58289/api/products/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62741' is therefore not allowed access.

This error is because the remote resource, in this case the remote service which is another ASP.NET Web API 2 site on the same machine (localhost), does not allow this origin because of the missing 'Access-Control-Allow-Origin' header in the response. The origin itself is the requesting address and will be sent in the request as the 'Origin' header. The request in this particular case was:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,nb;q=0.6,sv;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:58289
Origin:http://localhost:62741
Referer:http://localhost:62741/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36

Note the origin request header above. I have enabled CORS on the remote site on the same machine but configured it to deny this address. First, to enable CORS in a MVC Web API 2 website/webapplication, install the following nuget package: Microsoft ASP.NET Web API 2.2 Cross-Origin Support 5.2.3

Install-Package Microsoft.AspNet.WebApi.Cors

Next up, edit the class WebApiConfig in the App_Start folder:

   public static void Register(HttpConfiguration config)
   {

            config.EnableCors(); 
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
  }

The line that was added here in addition to the default setup is the line:
config.EnableCors(); 
It is possible to allow all calls to this remote site by setting up the web.config file with the following in <system.webServer><httpProtocol>:

    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>

However, this will actually not always be desired as often one knows which origin that will call this remote resource (site) and it is possible to do this programatically. So for now, commenting out this line in web.config and in the following example we use the [EnableCors] attribute:

using ProductsApp.Models;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.Description;

namespace ProductsApp.Controllers
{

    [EnableCors(origins: "http://localhost:62742", headers: "*", methods: "*")]
    public class ProductsController : ApiController
    {

        private readonly Product[] products = new Product[]{
            new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
            new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
            new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
        };

        public IEnumerable<Product> GetAllProducts()
        {
            return products; 
        }

      
        public async Task<IHttpActionResult> GetProduct(int id)
        {
            Product product = await GetProductAsync(id);
            if (product == null)
            {
                return NotFound(); 
            }
            return Ok(product); 
        }

        private async Task GetProductAsync(int id)
        {
            await Task.Delay(1000); 
            var product = products.FirstOrDefault(p => p.Id == id);
            return product;
        }      

    }

}

The following CORS setup was applied to the entire Web API v2 controller, which inherits from API Controller:
[EnableCors(origins: "http://localhost:62742", headers: "*", methods: "*")]
Here, the orgins property can list up (comma-separated) the allowed origins. Wildcards can be used here. The headers and methods configure further the setup of CORS. The [EnableCors] attribute can be applied to a controller or to a method inside the Web API v2 controller for fine-grained control. It is possible to do custom policy of CORS by using instead of [EnableCors] attribute a custom class that implements the interface
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
                AllowMultiple = false)]
public class EnableCorsForPaidCustomersAttribute :
  Attribute, ICorsPolicyProvider
{
  public async Task GetCorsPolicyAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var corsRequestContext = request.GetCorsRequestContext();
    var originRequested = corsRequestContext.Origin;
    if (await IsOriginFromAPaidCustomer(originRequested))
    {
      // Grant CORS request
      var policy = new CorsPolicy
      {
        AllowAnyHeader = true,
        AllowAnyMethod = true,
      };
      policy.Origins.Add(originRequested);
      return policy;
    }
    else
    {
      // Reject CORS request
      return null;
    }
  }
  private async Task IsOriginFromAPaidCustomer(
    string originRequested)
  {
    // Do database look up here to determine if origin should be allowed
    return true;
  }
}
Note here that we can do a database lookup inside the method IsOriginFromAPaidCustomer above. The class inherits from attribute, so one will use this attribute instead. We can add properties for further customization. Using a database-lookup will let us have control to which callers we allow to do a CORS call from their (Java)scripts without having to recompile, since the EnableCors attribute specifies the allowed origins hardcoded. There are further details of CORS, but this is really what is required to get successful ajax calls like the one below to work and avoiding the CORS violation.

    <script>

        $(document).ready(function () {

            var uri = 'http://localhost:58289/api/products/'; 

            $.ajax({
                url: uri,
                success: function (data) {
                    $.each(data, function (key, item) {
                        $('<li>', { text: formatItem(item) }).appendTo($('#products'));
                    });
                }
            });

            function formatItem(item) {
                return item.Name + ': $' + item.Price + ' ID: ' + item.Id;
            }

        });

    </script>

If it is desired to not use CORS (Cross Origin Resource-Sharing) for a given method or controller, use the [DisableCors] attribute. It is also possible to set up [EnableCors] with setting methods = "", i.e. no methods (HTTP Verbs) should be allowed CORS.

Saturday 14 March 2015

Resharper inspecting consistent locking of objects

Resharper has got a great inspection of your code of many different aspects, such as consistent locking of objects. An example is shown below, I have been using Resharper 9.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InconsistentLocking
{
    class Program
    {

        private static readonly object Locker = new object();


        private static readonly List<object> fooness = new List<object>(); 

        static void Main(string[] args)
        {

            DoSomeFoo(); 

        }

        private static void DoSomeFoo()
        {
            lock (Locker)
            {
                fooness.Add("Foo");
            }

            lock (Locker)
            {
                fooness.Remove("Foo");
            }

            lock (Locker)
            {
                fooness.Add("Baze");
            }

            //Resharper warning next - The field is sometimes used inside synchronized block and sometimes without synchronization 

            fooness.Remove("Baze");

            lock (Locker)
            {
                foreach (var foo in fooness)
                {
                    Debug.WriteLine(foo.ToString());
                }
            }


        }

    }
}

The code shows a simple example of using the list called fooness. The warning shows that for the line fooness.Remove("Baze"); that one is not locking the resource, in this case a list in memory called fooness. To fix the warning, just hit Alt+Enter Resharper Shortcut and the code will surround the resource with the lock block again.