VS 2013 RIA Service serialise child entities

The code below is an example of how you can use data contract serializer to serialize child entities to send as a json string property on parent object and then de-serialise the child entity in the Insert method of the parent entity in the RIA implementation

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.ServiceModel.DomainServices.Server;
using System.Text;

namespace Commerce.Catalogue.SageServer
{    
    public class Kit
    {
        [Key]
        public long Id { get; set; }
        public string Description { get; set; }
        public string CompList { get; set; } 
        public decimal Price { get; set; }
        [Include]
        [Composition]
        [Association("Kit_Components", "Id", "KitId")]       
        public ICollection Component { get; set; }
    }

    [DataContract]
    public class Component
    {
        [Key]
        [DataMember]
        public long Id { get; set; }
        [DataMember]
        public long KitId { get; set; }
        [DataMember]
        public string ComponentItemNo { get; set; }
        [DataMember]
        public int Qty { get; set; }                
    }

    public class SageService : DomainService
    {
        [Query(IsDefault = true)]
        public IQueryable GetKits()
        {
            return Enumerable.Empty().AsQueryable();   
        }

        [Update]
        [Invoke]
        public void UpdateKit(Kit kit)
        {
            var desc = kit.Description;
            var test = "hello";
        }

        [Insert]
        [Invoke]
        public void InsertKit(Kit kit)
        {
            var desc = kit.Description;
            var kitComp = new List();
            var compList = kit.CompList.Split('|').ToList();
            foreach (var comp in compList)
            {
                kitComp.Add(ReadToObject(comp));
            }

            var test = "hello";
        }

        [Delete]
        [Invoke]
        public void DeleteKit(Kit kit)
        {
            
        }

        // Deserialize a JSON stream to object.
        public static Component ReadToObject(string json)
        {
            var deserializedComponent = new Component();
            MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
            DataContractJsonSerializer ser = new DataContractJsonSerializer(deserializedComponent.GetType());
            deserializedComponent = ser.ReadObject(ms) as Component;
            ms.Close();
            return deserializedComponent;
        }
    }
}

In the RIA service client environment (lightswitch or Silverlight), you can serialize the child entity as shown by the below code:


 partial void Publish_Execute()
        {
            foreach (var item in selectedStocks)
            {
                var comp = new List();
                comp.Add(new Component{ComponentItemNo = "AB12", Id=1, KitId = 1,Qty = 2});
                comp.Add(new Component { ComponentItemNo = "CD40", Id = 2, KitId = 1,Qty=3 });
                var compStringList = new List();
                comp.ForEach(x => compStringList.Add(WriteFromObject(x)));
                
                var kit = DataWorkspace.SageServiceData.Kits.AddNew();
                kit.Id = 1;
                kit.Description = "Test Kit";
                kit.Price = 2.20M;
                kit.CompList = string.Join("|", compStringList.AsEnumerable());
                DataWorkspace.SageServiceData.SaveChanges();               
            }
        }

        // Serialize object to a JSON stream.
        public static string WriteFromObject(Component comp)
        {
            //Create a stream to serialize the object to.
            MemoryStream ms = new MemoryStream();

            // Serializer the User object to the stream.
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Component));
            ser.WriteObject(ms, comp);
            byte[] json = ms.ToArray();
            ms.Close();
            return Encoding.UTF8.GetString(json, 0, json.Length);

        }
HTH

Lightswitch many to many query filter format

If you have a lightswitch schema with a many to many relationship such as product-->productcategorymap<--category then you can add a parameter to your query such as categoryId (set as optional and not connected to a filter), link that parameter to the categories table (after adding it to your screen in the screen designer so you can display an auto complete list) and then add code similar to the below code in the query preprocessor handler of your query entity. Remember there is no need to implement query parameters mapped to entity properties. You just have to write code for the "free/unbound parameters":

In the code snippet below, a category entity is nested, so a  category references another category as its parent, so that specialised case where we match all sub categories of a given parent category Id is also handled.

 if (CategoryId.HasValue)
        query = query.Where(product => product.ProductCategoryMaps.Any(
			map => map.CategoryId == CategoryId 
			|| map.Category.ParentCategory.categoryID == CategoryId));

Sagepay server integration (.Net) with SSL pitfalls

Well, considering this took me a while to figure out, it might very well come in handy for you.

If you are integrating Sagepay server method on a Windows Server 2012 (IIS 8) server and in particular serving your payment pages over SSL, (this will imply the url you supply to sagepay aka NotificationUrl for handling the http POST response from Sagepay is an https url. I don't see why you wouldn't use SSL anyway), then one issue you might face is Server Name Indication. You may read all about SNI from here.

How does it affect your integration, well it turns out if your were to tick the server name indication checkbox shown below then Sagepay fails to contact your server and site with the notification response.

 

It gets particularly difficult to spot if your test/staging server runs IIS 7.x or IIS 6 which does not provide SNI support but your production server provides the support and you enable it without realising the problem.

So why does Sagepay's http POST fail under SNI? Well I don't know the inner workings/implementation details of Sagepays http post but SNI support is limited to specific browsers on specific operating systems as specified in the above linked wikipedia article so it is very likely Sagepay's implementation does not send the 'virtual server name' as part of the SSL client handshake request  (used loosely, you need to dig deeper into SNI to understand). This article might help.

Hopefully this helped you find the solution a bit quicker than I did. Sagepay's support sent me a list of things to check and this was not one of them so obviously they haven't noticed this one yet.

Cheers!

Html helper for list of hidden Inputs from Name Value Pair string

Recently, while working on a project to integrate a payment provider via the hosted payment page approach embedded within an Iframe, I needed a simple Html Helper for ASP.Net MVC which took in a name value pair string like FIRSTNAME=Mike&LASTNAME=Teye&Age=25 and generated a list of html hidden input tags for use as part of a form post whose response was then rendered in an Iframe tag.

I admit it's a specialised helper and so I don't forsee many people needing it, but then again should you be one of those few who needed it, the below class represents my attempt at such a helper:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web.Mvc;

namespace Kraft.Web.Models.Extensions
{
    public static class HtmlHelperExtensions
    {
        public static MvcHtmlString HiddenFieldsListFor(this HtmlHelper htmlHelper, Expression> expression)
        {
            var name = ExpressionHelper.GetExpressionText(expression);
            var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            return HiddenFieldsList(htmlHelper, name, metadata.Model as string);
        }

        private static MvcHtmlString HiddenFieldsList(this HtmlHelper helper, string nameValuePairPropertyName, string nameValuePairPayload)
        {
            var stringBuilder = new StringBuilder();
            var nameValuePairs = nameValuePairPayload.Split('&').ToList();
            nameValuePairs.ForEach(nvp => stringBuilder.Append(CreateHiddenInput(nvp).ToString(TagRenderMode.SelfClosing)));
            var div = new TagBuilder("div");
            div.MergeAttribute("class", "hiddenFields");
            div.InnerHtml = stringBuilder.ToString();
            return MvcHtmlString.Create(div.ToString());

        }

        private static TagBuilder CreateHiddenInput(string nameValuePair)
        {
            var hiddenInput = new TagBuilder("input");
            var nvpPortions = nameValuePair.Split('=');
            hiddenInput.MergeAttribute("type", "hidden");
            hiddenInput.MergeAttribute("id", nvpPortions[0]);
            hiddenInput.MergeAttribute("name", nvpPortions[0]);
            hiddenInput.MergeAttribute("value", nvpPortions[1]);
            return hiddenInput;
        }
    }
}

You can use the helper in an MVC razor view like so (where NvpPayload is a view model property containing your name value pair string):

@Html.HiddenFieldsListFor(model => model.NvpPayload)

Hope you find it helpful.

Integrating SandCastle Help File Builder with TFS 2012 build

Sandcastle has been around for a while. Its usage has however been dificult and unappealing until Sandcastle Help File Builder codeplex project came into the picture.

The recent version of Sandcatsle help file builder makes it even more easier by providing a Visual Studio plugin which facilitates the management of the help file generation through familiar visual studio project properties and also allows referencing projects which are part of your solution in your SHFB project.

The only piece of the puzzle missing is the integration of the build of the document project as part of a CI build on Team Foundation Server TFS. There are a few outdated approaches to this available online when I googled. I felt there should be an easier integration now that there is a VS plugin, so I set out to check this out and in turns out it is very easy. So the below is how I did the simple integration:

To Create a visual studio SHFB project, download and install SHFB on your development machine using the guided installer. You will have to install the Visual Studio plugin as part of the install. Create a new project in Visual Studio by using the documentation subsection of your choice language. The details of configuring the help file builder are the same as that for the standalone Sandcastle Help file builder GUI.

First of all you will need to download the latest version of Sandcastle Help File builder (which ships with the VS plugin).

Extract the files from the zip archive and use the guided installer from the root folder to install sandcastle and help file compiler onto

the build controller machine.

You will have to restart the build controller machine to reload new path environment variables created by the installer (SHFBROOT).

This environment variable is used within a sandcastle help file project to locate the help file compiler executables and serves the same purpose on the build agent machine as it does on a local development machine.

You will need one final modification to the help file builder project. First unload the project by right clicking on the project name in solution explorer and select unload project. Then open the project file xml by right clicking and selecting open with xml editor. As per this post, replace the line immediately below the following line:


With the following code:

  

.\Help\
$(OutDir)

Ignore SignalR Persistent Connections in New Relic

I had a problem recently at work where the SignalR.Hosting.AspNet.AspNetHandler was displaying high response times in our New Relic monitoring. I came across this SO blog post which offerred some workarounds for the problem. I was however using an older version of SignalR (a pre 1.0 release) and the options listed in the blog post failed to resolve my particular case.

What worked for me eventually was to hook into the PostMapRequestHandler event of the Application class in global.asax and then check for the handler. Because that event fires after a handler has been selected to process the request, we are able to tell what type of handler has been selected and then use the NewRelic Agent API (You will need to add this to your project via Nuget, search for NewRelic.Api.Agent) to ignore monitoring as per the code below:

 protected void Application_PostMapRequestHandler()
 {
     if (HttpContext.Current.Handler is SignalR.Hosting.AspNet.AspNetHandler)
     {
          NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
     }
}

This approach works even for later versions of SignalR (1.0+) in which case you have to match the OWIN based handler as shown below:

protected void Application_PostMapRequestHandler()
{
     if (HttpContext.Current.Handler is Microsoft.Owin.Host.SystemWeb.OwinHttpHandler)
     {
          NewRelic.Api.Agent.NewRelic.IgnoreTransaction();
     }
} 

Happy coding!

MvcSitemapProvider Implementation : Lessons learnt

1.If you happen to be using any active directory based role provider, make sure the website is running with default authentication turned off and windows authentication turned on. You can do this easily by configuring your website to run on IIS or IIS Express.

2. For any node configured in the sitemap file using the controller and action values, make sure the controller and action are actually available. The MvcSitemapProvider fails silently and does not throw any exceptions to make you aware of why it is failing. This means you cannot simply bash up some dummy routes and expect it to work.

3. If you enable security trimming by setting "securityTrimmingEnabled" to true on the provider node in web.config, then you need to specify a roles="*" for nodes accessible to all users.

4. If you use "#" for url values, they will not show up while security trimming is enabled.

5. I also think, parent nodes should be at a higher url level to child nodes otherwise the parent node is not displayed, I haven't thoroughly verified this so I might be wrong on this one.

6. I tried using resourceKey settings in the sitemap file and the corresponding nodes were not rendered by the menu helper.

Custom Validator IsValid Overload Precedence

 

When you derived a Custom DataAnnotations Validator from the default ValidationAttribute class, you have a choice of two overrides to implement your custom validation logic. You may override one of the following methods depending on your objectives.

  • public bool IsValid(object value)
  • protected ValidationResult(object value, ValidationContext validationContext)

Recently, I had a situation where I implemented custom validation (ie. The validator did not use the built in MVC DefaultModelBinder which implemented validation). I hooked up a custom model binder and also needed an accompanying custom validator. I ended up using the DataAnnotations Validator from within my code like so:

 var context = new ValidationContext(wizardBindModel, null, null) {MemberName = item.PropertyInfo.Name};
                        var validationResults = new Collection();
                        if (!Validator.TryValidateValue(value, context, validationResults, new Collection(){validationAttribute}))
                        {
                            validationResults.ToList().ForEach(r => modelState.AddModelError(r.MemberNames.First(), r.ErrorMessage));
                        }    
I was then wondering, what happened if my validation attribute implemented both IsValid(object) and IsValid(object, ValidationContext). I did not find an explanation through google, so I tried the code and found out by experience that the IsValid(object,ValidationContext) has precedence over the IsValid(object) method. If you override both methods, only the IsValid(object,ValidationContext) version will be invoked by the DataAnnotations TryValidateValue method. HTH.

Styling Asp.Net MVC validation errors as tooltips

I recently had to find a way of styling asp.net Mvc validation errors as tooltips/speech bubbles/hints in order to preserve consistency of the UI on a legacy system. I was able to achieve this with some simple jquery, some css modification and a very handy jquery plugin called jquery validation hooks. The css and javascript code are listed below. Follow the instructions at the linked jquery validation hooks page.

 $(document).ready(function () {
        $('form').addTriggersToJqueryValidate().triggerElementValidationsOnFormValidation();
        $('form').formValidation(function (element, result) {
            $(".field-validation-error").each(function (e) {
                var errorSpan = $(this);
                var relatedInput = $(this).parent().children("input:first");
                relatedInput.hover(
                        function () {
                            errorSpan.show();
                        },
                        function () {
                            errorSpan.hide();
                        }
                    );
                 errorSpan.hide();
            });
        });
    });
/* VALIDATION ERROR SPAN */

.field-validation-error span
{
  color:#ffffff;
  margin-left: 5px;
  display:none;
  font-size:12px;
  font-family:arial;
  padding:.5em 1em;
  padding-top:5px;
  position:relative;
  text-align:center;
  vertical-align:middle;
  border:1px solid silver;
  background-color:#ff0000;
}

.field-validation-error span:after 
{
 content:"";
  display:inline-block;
  font-size:2em;
  height:20px;
  width:20px;
  position:absolute;
  left:-0.4em;
  top:0.1em;
 background: url(pointer.gif) left center no-repeat;
}

The pointer image is attached for your convenience. Fell free to improve the css appropriately.

Unity Interception Behavior - Crucial point

I tend to forget the reason for the abnormal syntax when invoking the intercepted method in a Unity interception behavior class. I mean this:

IMethodReturn msg = getNext()(input, getNext);

The quote below reminds me of the reason. The getNext parameter is a delegate which returns a delegate, but also takes that original delegate as an input: "The Invoke method has two parameters: input and getNext. The input parameter rapresents the current call to the original method, the getNext parameter is a delegate to execute to get the next delegate in the behavior chain".