Archive for December 2014

See descriptive Enitity Validation Errors in exception message

By default, Entity Validation Errors are not described in the DbEntityValidationException that is thrown.

If you want those displayed, here is how:

Locate your DbContext object in your project. Overload the SaveChanges() message as follows:

        public override int SaveChanges()
        {            
            try
            {
                return base.SaveChanges();
            }
            catch (DbEntityValidationException eve)
            {
                var errorMsg = new StringBuilder(eve.Message + Environment.NewLine);
                foreach (var validationResult in eve.EntityValidationErrors)
                {
                    foreach (var error in validationResult.ValidationErrors)
                    {
                        errorMsg.Append(validationResult.Entry.Entity + ": ");
                        errorMsg.Append(error.ErrorMessage + Environment.NewLine);
                    }
                }
                // Use the same exception type to avoid downstream bugs with code that catches this
                throw new DbEntityValidationException(errorMsg.ToString(), eve.EntityValidationErrors, eve);
            }
        }

I can see how the decision to not include them by default is good. Doing so could be an information disclosure security issue. However, if wrapped in a WCF service where the the entities are used as the DataContract or POCO objects, then there really isn’t much information additional information provided than what is in the wsdl.

An MVC DropDownListFor that supports all attributes

So I need a DropDownListFor that allows me to create any attribute for the select or option tags. Obviously the attributes for each option tag should come from a property in an object that is provided in a collection. I also eliminate the need of converting a collection of your custom object to a collection of SelectListItem.

Remember a DropDownList in HTML looks like this:

<select>
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>

The current DropDownListFor uses a list of SelectListItem objects to create the option tags. However, SelectListItem only supports the value attribute and the inner text (the text between the open option tag and the close option tag). Support for any attribute should be provided.

First, I create a model to hold the attribute data. It is a very small class with only five properties, but looks like a big class due to the extensive comments.

using System.Collections.Generic;

namespace LANDesk.Licensing.Wavelink.Models
{
    public class HtmlSelectListModel<T>
    {
        /// <summary>
        /// That collection of data elements from which to create a the select options.
        /// </summary>
        public IEnumerable<T> DataObjects { get; set; }

        /// <summary>
        /// Often there is an option on top called "--Select item--" that has an empty value.
        /// </summary>
        public string EmptyValueText { get; set; }

        /// <summary>
        /// A bool value that checks for whether EmptyValueText is used or not
        /// </summary>
        public bool ShouldUseEmptyValue
        {
            get { return !string.IsNullOrWhiteSpace(EmptyValueText); }
        }

        /// <summary>
        /// This will add attributes to the <select></select> html tag.
        /// The key is the attribute, the value is the value.
        /// For example:
        ///     SelectAttributes.add("id", "select-id-1");
        /// Would result in this html:
        ///     <select id="select-id-1"></select>
        /// </summary>
        public Dictionary<string, string> SelectAttributes
        {
            get { return _SelectAttributes ?? (_SelectAttributes = new Dictionary<string, string>()); }
            set { _SelectAttributes = value; }
        } private Dictionary<string, string> _SelectAttributes;

        /// <summary>
        /// This will add attributes to the <option></option> html tag in a select list.
        /// The key is the attribute, the value is the property on the object that contains the value.
        /// A list of objects will be used to create the options. Using reflection, the property with a
        /// name matching the value will be found. If the value is "Country" then a property name Country
        /// will be found using reflection. 
        /// 
        /// Note: If inner-text is used it will not be an attribute but will be the text between the
        ///       opening and closing tags.
        /// 
        /// For example:
        ///     OptionAttributes.add("value", "CountryTwoLetter");
        ///     OptionAttributes.add("innter-text", "Country");
        /// If the the list had to objects and the Country values were "United States" and "Canada",
        /// and the CountryTwoLetter values were "US" and "CA", then the result would be this html:
        ///     <option value="US">United States</option>
        ///     <option value="US">United States</option>
        /// 
        /// Html data-[name] attributes are supported here as well.
        /// </summary>
        public Dictionary<string, string> OptionAttributes
        {
            get { return _OptionAttributes ?? (_OptionAttributes = new Dictionary<string, string>()); }
            set { _OptionAttributes = value; }
        } private Dictionary<string, string> _OptionAttributes;
    }
}

Next add an extension method to HtmlHelper.

using LANDesk.Licensing.Wavelink.Models;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace System.Web.Mvc
{
    public static class DrownDownListHelper
    {
        /// <summary>
        /// Adds increased attributed functionality to DropDownListFor.
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TProperty"></typeparam>
        /// <typeparam name="T">The type of object in a list.</typeparam>
        /// <param name="htmlHelper">The object this method attaches to.</param>
        /// <param name="expression">The object the selected value binds to.</param>
        /// <param name="listModel">The Model object for creating this list.</param>
        /// <returns>MvcHtmlString - Html for Razor pages.</returns>
        public static MvcHtmlString DropDownListWithAttributesFor<TModel, TProperty, T>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, HtmlSelectListModel<T> listModel)
        {
            var dropdown = new TagBuilder("select");
            foreach (var selectAttribute in listModel.SelectAttributes)
            {
                dropdown.Attributes.Add(selectAttribute.Key, selectAttribute.Value);
            }
            string currentValue = null;
            var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            if (metadata != null && metadata.Model != null)
                currentValue = metadata.Model.ToString();

            var optionsBuilder = new StringBuilder();
            foreach (T item in listModel.DataObjects)
            {
                BuildOptionTags(listModel, optionsBuilder, item, currentValue);
            }
            if (string.IsNullOrWhiteSpace(currentValue) && listModel.ShouldUseEmptyValue)
            {
                optionsBuilder.Insert(0, "<option value=\"\">" + listModel.EmptyValueText + "</option>");
            }
            dropdown.InnerHtml = optionsBuilder.ToString();

            return new MvcHtmlString(dropdown.ToString(TagRenderMode.Normal));
        }

        internal static void BuildOptionTags<T>(HtmlSelectListModel<T> listModel, StringBuilder optionsBuilder, T item, string selectedValue)
        {
            var optionAttributes = GetOptionAttributes(listModel, item);
            string innerText = GetOptionInnerText(optionAttributes);

            if (optionsBuilder == null) { optionsBuilder = new StringBuilder(); }
            optionsBuilder.Append("<option ");
            bool defaultValueFound = false;
            foreach (var attribute in optionAttributes)
            {
                optionsBuilder.Append(string.Format("{0}=\"{1}\" ", attribute.Key, attribute.Value));
                if (attribute.Value == selectedValue)
                {
                    optionsBuilder.Append("selected=\"selected\" ");
                    defaultValueFound = true;
                }
            }
            optionsBuilder.Append(">" + innerText + "</option>");
        }

        internal static string GetOptionInnerText(IDictionary<string, string> optionAttributes)
        {
            string innerText;
            if (optionAttributes.TryGetValue("inner-text", out innerText))
            {
                optionAttributes.Remove("inner-text");
            }
            return innerText;
        }

        internal static Dictionary<string, string> GetOptionAttributes<T>(HtmlSelectListModel<T> listModel, T item)
        {
            var properties = item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => listModel.OptionAttributes.Values.Contains(p.Name));
            var optionAttributes = new Dictionary<string, string>();
            foreach (var p in properties)
            {
                var p1 = p;
                foreach (var oa in listModel.OptionAttributes.Where(oa => p1.Name == oa.Value))
                {
                    optionAttributes.Add(oa.Key, p.GetValue(item, null).ToString());
                }
            }
            return optionAttributes;
        }
    }
}

Now you can use this in an MVC razor cshtml page. You will need a using statement like this:
@using MyNamespace.Models

    <div class="form-group">
        @Html.LabelFor(model => model.Customer.State, new { @class = "control-label col-md-2", required = "required" })
        <div class="col-md-10">
            @Html.DropDownListFor2(model => model.Customer.State, 
                new HtmlSelectListModel<State>
                {
                    DataObjects = CountryManager.Instance.States,
                    EmptyValueText = "- Select a State -",
                    SelectAttributes = new Dictionary<string, string> { { "Id", "Customer_State" }, { "Name", "Customer.State" } },
                    OptionAttributes = new Dictionary<string, string>
                                        {
                                            { "value", "StateCode" }, { "inner-text", "StateName" }, { "data-country", "CountryCode" } 
                                        }
                }
            )
            @Html.ValidationMessageFor(model => model.Customer.State)
        </div>
    </div>

It will make some awesome html. It even allows for adding data-[name] attributes. I needed a data-country attribute, which is why I wrote this class.

<select id="Customer_State" name="Customer.State">
    <option value="" >- Select a State -</option>
    <option value="AB" data-country="CA">Alberta</option>
    <option value="AK" data-country="US">Alaska</option>
    <option value="AL" data-country="US">Alabama</option>
    <option value="AR" data-country="US">Arkansas</option>
    <option value="AZ" data-country="US">Arizona</option>
    <option value="BC" data-country="CA">British Columbia</option>
    <option value="CA" data-country="US">California</option>
    <option value="CO" data-country="US">Colorado</option>
    <option value="CT" data-country="US">Connecticut</option>
    <option value="DC" data-country="US">District of Columbia</option>
    <option value="DE" data-country="US">Delaware</option>
    <option value="FL" data-country="US">Florida</option>
    ...
</select>

If you have any feedback, I would love to hear it. Please comment.

Authenticating to Salesforce with Silenium in C#

It is pretty easy to authenticate to Salesforce with Silenium in C#. Here are the steps.

  1. Add the following NuGET package to your project:
    Silenium WebDriver
  2. Use the following code:
        public static void LoginToSalesforce(string username, string password)
        {
            IWebDriver driver = new FirefoxDriver();
            driver.Url = "https://test.salesforce.com";
            driver.Navigate();
            var userNameTextBox = driver.FindElement(By.Id("username"));
            userNameTextBox.SendKeys(username);
            var passwordTextBox = driver.FindElement(By.Id("password"));
            passwordTextBox.SendKeys(password);
            var loginButton = driver.FindElement(By.Id("Login"));
            loginButton.Submit();
        }

Yes it is that easy.

EntityUpdater Generic helper for Entity Framework

So I am using Entity Framework (EF) more and more and I really like it. However, I’ve come across a problem when using WCF services and EF that doesn’t look to be perfectly solved.

Let me share my use case.

I have many entities but in this case, let’s use Customer and CustomerSite. I am using that Entity as a POCO object for a WCF service as well. I have two Systems. SAP and a custom C# licensing system, which is where I am using WCF and EF.

Customer
– CustomerId
– CustomerName

Customer Site
– CustomerSiteId
– CustomerId
– SiteName
– Address1
– Address2
– State
– Country
– Zip
– Website
– SapCustomerId

Let’s say that someone changes the Address for a customer in SAP. A post is made with the new Address. I tried a couple of built-in Entity Framework methods, but I’ve been unable to figure out how the front end client can update a single property without first querying over WCF for the existing values and having the client side update the changed values. To me, this seems to be a broken process. The client has to query the current object, which results in a call that has to traverse over the wire to the WCF service, then to the database through EF, then back to WCF and back over the wire to the client. Then logic has to exist on the client to update the appropriate fields. The client now needs a lot of logic it otherwise shouldn’t need.

If the client wants to update only one field, Address1, the client should be able to send an update request that contains only CustomerSiteId and Address1 with everything else should be left blank.

However, the logic to do this work on the server side seems difficult if not impossible without some data from the client. WCF gets in the way. The object is created by the WCF service and every field exists in the object and none of the fields are marked as “updated” or not. If only one field is changed, the other fields are default values in the instantiated object. How can the server know which fields are updated?

Well, if the client is sending a change and the change is not a default value, then we can ignore updates for properties that use default values. However, what if we want to change to a default value? What if, for example, the default value of Address2 is null. What if you want to change the database value back to null?

What if I want to update all the address fields but leave the CustomerId the same?

  1. Write a separate WCF method every time there is a field that might be updated by itself.

    Yeah, this is a nightmare. It isn’t really a solution.

  2. Write a method that any WCF service can call that takes in an Entity Type, an Id and a list of property names and their corresponding values.

    While this would work, it breaks the idea of using the Poco object. The ability to use a simple entity object is nice. Breaking away from the Entity object to a generic object like this seems the wrong thing to do. It would work, though. It would need client code to convert entities to this new object type that has an Id and a property value dictionary. Also, now the code is not clear. Instead of calling UpdateCustomer(customer), I would call UpdateEntity(myObject), which just isn’t as clear or as readable.

  3. Have a single generic method on the server that any WCF service method could call. The method would loop through the entity object and if a property’s value is default or null, that value isn’t updated.

    I like this because the logic is on the server. I can have UpdateCustomer and UpdateCustomerSite and each can call this method easily. The one problem, what if I want to set the value to null? This wouldn’t work.

  4. Have my WCF methods on the WCF server that takes in an IEnumerable of changed property names, then have generic code to loop through the Entity and mark the appropriate properties as “Changed”.

    I like this too, but if I only change one property to an actual value, I would really like to avoid creating the IEnumerable.

  5. Have both methods 3 and 4 above.

    This is what I am going with.

I created this class to help me with this.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Reflection;

namespace Rhyous.Db.Common
{
    public class EntityUpdater<T> where T : class
    {
        /// <summary>
        /// Updates the value of all properties with a value other than null or the default value for the class type. 
        /// </summary>
        /// <param name="entity">The entity to update</param>
        /// <param name="entry">A DbEntityEntry<T> entry object to mark which propeties are modified.</param>
        public void Update(T entity, DbEntityEntry<T> entry)
        {
            var props = from propertyInfo in entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => !Attribute.IsDefined(pi, typeof(NotMappedAttribute)))
                        let val = propertyInfo.GetValue(entity, null)
                        where !IsNullOrDefault(val) && !IsCollection(val)
                        select propertyInfo;
            foreach (var pi in props)
            {
                entry.Property(pi.Name).IsModified = true;
            }
        }

        /// <summary>
        /// Updates the value of any property in the updatedPropertyNames list. 
        /// </summary>
        /// <param name="entity">The entity to update</param>
        /// <param name="updatedPropertyNames">The list of properties to update.</param>
        /// <param name="entry">A DbEntityEntry<T> entry object to mark which propeties are modified.</param>
        public void Update(T entity, IEnumerable<string> updatedPropertyNames, DbEntityEntry<T> entry)
        {
            var propInfoCollection = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in from pi in propInfoCollection
                               from updatedPropertyName in updatedPropertyNames
                               where pi.Name.Equals(updatedPropertyName, StringComparison.CurrentCultureIgnoreCase)
                               select pi)
            {
                entry.Property(pi.Name).IsModified = true;
            }
        }

        /// <summary>
        /// Checks if any object is null or the default value for the class type. 
        /// </summary>
        /// <typeparam name="TT">The object class</typeparam>
        /// <param name="argument">The object to test for null or default.</param>
        /// <returns></returns>
        public static bool IsNullOrDefault<TT>(TT argument)
        {
            // deal with normal scenarios
            if (argument == null) return true;
            if (Equals(argument, default(TT))) return true;

            // deal with non-null nullables
            Type methodType = typeof(TT);
            if (Nullable.GetUnderlyingType(methodType) != null) return false;

            // deal with boxed value types
            Type argumentType = argument.GetType();
            if (argumentType.IsValueType && argumentType != methodType)
            {
                object obj = Activator.CreateInstance(argument.GetType());
                return obj.Equals(argument);
            }

            return false;
        }

        /// <summary>
        /// Check if an object is a collection. This is to use to ignore complex types.
        /// </summary>
        /// <typeparam name="TT">The object class</typeparam>
        /// <param name="obj">The object to test.</param>
        /// <returns></returns>
        public static bool IsCollection<TT>(TT obj)
        {
            return obj.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>));
        }
    }
}

Now, I can use this class in my separate WCF services as follows.

        /// <summary>
        /// Updates the value of all properties with a value other than null or the default value for the type.
        /// Any property that is not set to a value other than null or default is ignored.
        /// </summary>
        /// <param name="customerSite">The customerSite entity to update</param>
        public int UpdateSiteSimple(CustomerSite customerSite)
        {
            UpdateSite(customerSite, null);
        }

        /// <summary>
        /// Updates the value of any property in the customerSite contained in the updatedPropertyNames list. 
        /// The values of any properties not in the updatedPropertyNames list are ignored.
        /// </summary>
        /// <param name="customerSite">The customerSite entity to update</param>
        /// <param name="updatedPropertyNames">The list of properties to update.</param>
        public int UpdateSite(CustomerSite customerSite, IEnumerable<string> updatedPropertyNames)
        {
            if (customerSite == null) { throw new Exception("The customerSite cannot be null"); }

            using (var db = new MyDbContext())
            {
                db.CustomerSites.Attach(customerSite);
                var entry = db.Entry(customerSite);
                var updater = new EntityUpdater<CustomerSite>();
                if (updatedPropertyNames == null || !updatedPropertyNames.Any())
                    updater.Update(customerSite, entry);
                else
                    updater.Update(customerSite, updatedPropertyNames, entry);
                db.SaveChanges();
            }
            return customerSite.CustomerSiteId;
        }

If you like this code and find it useful please comment.

Currently, it ignores complex types and won’t update them. I could see attempting to update complex properties in the future.