Preloading View Model Data into a Knockout Model (Without the extra JSON call) in ASP.Net MVC

I’ve recently been playing around with Knockout and working it in with to my MVC apps.  It dramatically simplifies some of the complexities of keeping an interface up to date when performing JavaScript changes.

One of the very first issues I ran into was, how do I load in some initial data from C#?  The advertised and I assume the easiest way is to just make an extra get JSON call.  But what if I just need a few values to populate a dropdown?  Say a list of States.  Personally I think it’s a waste of an extra JSON call when it can just be embedded in the page itself. 

So let’s take a look at the C# view model:

public class Viewmodel
{
     public IEnumerable States {get; set;}
}

public class State
{
     public string Abbr {get; set;}
     public string Name {get; set;}
}

And our knockout model:

function AppViewModel() {
    var self = this;
    self.states = ko.observableArray();
}

ko.applyBindings(new AppViewModel());

Our goals is to populate the self.states member with our list from the C# view model.  Sure you can do the following code:

function AppViewModel() {
    var self = this;
    self.states = ko.observableArray();
}

var model = ko.applyBindings(new AppViewModel());

// url that gets the state object in json format
var url = 'some url';
$getJSON(url, function(results) {
     $.each(results, function(item, index){
          model.states.push(item);
     });
});

But wouldn’t it nice if we could just initialize the array without having to go back to the server?  Especially for such a small list.  There are times when the above code makes sense.  Consider the following:

var depts = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model.States.Select(a => new { id= a.Abbr, name=a.Name })));

function AppViewModel() {
    var self = this;
    self.states = ko.observableArray(states);
}

ko.applyBindings(new AppViewModel());

(Yes it’s using Razor syntax, but it can just as easily use the older syntax).  The line of code essentially takes the array of states and creates the raw javascript array as if it was hard coded in the page, which in turn can be easily loaded into an observable array.  It works fantastically with small lists (and can with large lists, but consider load times before deciding which way to go.

That’s about it.

Windows Azure Backups with Bacpac – Automating Cleanup (Part 3)

Welcome to part 3 of my azure backup series.  We’ll be looking at automating cleanup of your blob storage.  If you will be using this method of doing backups to blob storage (taking snapshots of the database every XX hours/days), eventually you’ll have a large build up of old backups that will be outdated.  So rather than logging in to the azure console every few days, why not automate the cleanup of your outdated bacpac files?

The following is a list of settings that are needed to get the cleanup working.

  • _storageAccountName – The name of the storage service account
  • _storageKey – One of the access keys for the storage account (primary or secondary, doesn’t matter).  Just make sure you don’t check it in to a repository!
  • _storageContainer – Name of the storage container you’d like your bacpac files to be put into.
  • _cleanupThreshold – # of days before a backup is considered outdated and deleted.  This needs to be a negative number, I do the conversion in my constructor to ensure it’s negative.

To do the overall cleanup, I take advantage of the managed APIs for the Azure Storage to get a list of all blobs in storage and then to delete them out.

First we want to setup a client, it’s fairly straight forward, we just pass in a connection string and it does the rest.

var storageAccount = CloudStorageAccount.Parse(
     string.Format(CloudStorageconnectionString, _storageAccountName, _storageKey));
var client = storageAccount.CreateCloudBlobClient();

Next, we need to tell the client which container we want to look at and get a list of all it’s contents.  Then we want to filter down the list so that it only shows blobs that are past the threshold (the ones we want to delete).

var container = client.GetContainerReference(_storageContainer);
var blobs = container.ListBlobs(null, true);
var filtered = blobs.Where(a => a is CloudBlockBlob && 
     ((CloudBlockBlob)a).Properties.LastModified < DateTime.Now.AddDays(_cleanupThreshold))
     .ToList();

Finally, we make the calls to do the deletions.  The below is the basic call used to delete the files, but in my full code I return a list of those blobs that were deleted.

foreach(var item in filtered)
{
     var blob = (CloudBlockBlob)item;
     deleted.Add(blob.Name);
     blob.Delete();
}

That’s fairly straight forward right?  Here is the code as a whole, this is an excerpt of the entire code but it’s what is necessary to do the cleanup.

Now sit back and pretend like you have to do your cleanups everyday to save the company money 🙂

Azure Backups Series:

Exchange Calendar Syncing with Exchange Web Services (EWS) API

I’ve been working with the Exchange Web Services managed API on and off for the past year and surprisingly there isn’t all that much documentation.  Sure there is the standard Microsoft documentation (here) but it only gives basic examples.  Which as it turns out worked out for the majority of the functions I need to handle for my project, but there is one problem that the API couldn’t handle.

The project that I’ve been working on is an appointment scheduling application.  The basics are that the application maintains a master calendar of a various number of people and they each specify when they are available for appointments and for what type of appointment.  These appointments are displayed in the program but are also written out to their exchange calendars.  Keeping these appointments in order would be all fine and dandy except the appointment aren’t read-only.

EWS does have a function that will supposedly aid in synchronizing the calendar to the database.  The function called “SyncFolderItems” takes a sync state (which it returns to you when you run the function) and using this sync state information EWS returns any changes to the calendar since that sync.  However it doesn’t seem to work all that well and appears to be quite fragile (it is probably worth noting that I am working against an Exchange 2007sp1 server and not 2010).  The sync might work at first but after some amount of time or some condition it just stops returning any changes at all.  And it’s hard to debug since EWS just tells me no changes happened.

This is the MyAppointment class that is used in the program.

public class MyAppointment
{
    public int Id { get; set; }
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public string Subject { get; set; }
    public string Body { get; set; }

    public string ExchangeId { get; set; }
}

The following is the code for using the EWS sync function.

public string SyncChanges(string mailboxId, IEnumerable<MyAppointment> appointments, string syncState)
{
    var service = InitializeService(mailboxId);

    var changeLog = service.SyncFolderItems(
        new FolderId(WellKnownFolderName.Calendar, mailboxId),
        PropertySet.FirstClassProperties, null, 512,
        SyncFolderItemsScope.NormalItems, syncState);

    foreach (var changedItem in changeLog)
    {
        var appt = appointments.Where(a => a.ExchangeId == changedItem.ItemId.UniqueId).FirstOrDefault();

        if (appt != null)
        {
            switch(changedItem.ChangeType)
            {
                case ChangeType.Update:
                    var appointment = (Appointment) changedItem.Item;
                    appointment.Start = appt.Start;
                    appointment.End = appt.End;
                    appointment.Subject = appt.Subject;
                    appointment.Body = appt.Body;

                    // write the change back to exchange

                    break;
                case ChangeType.Delete:

                    var newAppointment = new Appointment(service);

                    newAppointment.Start = appt.Start;
                    newAppointment.End = appt.End;
                    newAppointment.Subject = appt.Subject;
                    newAppointment.Body = appt.Body;

                    // write the change back to exchange

                    break;
                default:
                    break;
            }
        }
    }

    return changeLog.SyncState;
}

However the above code doesn’t work for whatever reason.  Instead I wrote the following function that essentially does the same thing, but only syncs data 2 months ahead.  It takes a few more lines of code but using Linq it makes it easy to do the comparisons.

public void SyncChanges(string mailboxId, IEnumerable<MyAppointment> myAppointments)
{
    // get appt one day before and 1 month out
    var searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And);
    searchFilter.Add(
        new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start, DateTime.Now.AddDays(-1)));
    searchFilter.Add(
        new SearchFilter.IsLessThanOrEqualTo(AppointmentSchema.End, DateTime.Now.AddMonths(2)));
    searchFilter.Add(
        new SearchFilter.IsEqualTo(ItemSchema.ItemClass, "IPM.Appointment"));
    // get back 512 results max
    var view = new ItemView(512);
    // make the remote call
    var service = InitializeService(mailboxId);
    var results = service.FindItems(
        new FolderId(WellKnownFolderName.Calendar, mailboxId), searchFilter, view);

    // get the distinct ids from exchange
    var exchangeIds = results.Select(a => a.Id.UniqueId);

    // get the distinct ones we have
    var dbIds = myAppointments.Select(a => a.ExchangeId);

    // find the ids that are in the db but not in exchange
    var missing = dbIds.Where(a => !exchangeIds.Contains(a));

    var newAppts = myAppointments.Where(a => missing.Contains(a.ExchangeId)).Select(
                        a => new Appointment(service) {Start = a.Start
                                                     , End = a.End
                                                     , Subject = a.Subject
                                                     , Body = a.Body});

    // get the exchange objects we do have in the db
    var appts = results.Where(a => !missing.Contains(a.Id.UniqueId) && dbIds.Contains(a.Id.UniqueId))
                       .Select(a => (Appointment)a);

    var changedAppts = new List();

    // find the changed appointments
    foreach (var appointment in appts)
    {
        // get the db appointment object
        var appt = myAppointments.Where(a => a.ExchangeId == appointment.Id.UniqueId).FirstOrDefault();

        // compare the time stamps and determine if we need to make a change
        if (appt != null)
        {
            if (appt.Start != appointment.Start || appt.End != appointment.End)
            {
                // make the changes
                appointment.Start = appt.Start;
                appointment.End = appt.End;
                appointment.Subject = appt.Subject;
                appointment.Body = appt.Body;

                // add it to the list of ones needed to change
                changedAppts.Add((Item)appointment);
            }
        }
    }

    // write the new and updated objects to exchange
}

The end result is that if a user moves or deletes an appointment managed by the program it can on interval go back and sync the calendar.

Safely Displaying Html Formatted User Content

Html escaping in ASP.NET MVC is a great way to prevent Cross-Site Scripting (XSS) attacks on your application.  The only problem I found was that sometimes an application needs to display formatted text and using the “Html.Encode(content)” will remove all formatting (as it is expected to).

So I have written a little extension method that enables specific html formatting to be allowed while still escaping potentally dangerous html.

public static class HtmlHelperExtensions
{
     private const string htmlTag = @&quot;&amp;lt;{0}&amp;gt;&quot;;

     public static string HtmlEncode(this HtmlHelper helper, string text)
     {
          // encode the string
          string encodedText = HttpUtility.HtmlEncode(text);

          // put the text in a string builder
          StringBuilder formattedEncodedText = new StringBuilder(encodedText);

          // replace the escaped characters with the correct strings to allow formatting
          // &lt;p&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;p&quot;), @&quot;&lt;p&gt;&quot;);
          // &lt;/p&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/p&quot;), @&quot;&lt;/p&gt;&quot;);

          // &lt;strong&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;strong&quot;), @&quot;&lt;strong&gt;&quot;);
          // &lt;/strong&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/strong&quot;), @&quot;&lt;/strong&gt;&quot;);

          // &lt;em&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;em&quot;), @&quot;&lt;em&gt;&quot;);
          // &lt;/em&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/em&quot;), @&quot;&lt;em&gt;&quot;);

          // &lt;span style=&quot;text-decoration:underline;&quot;&gt;
          string underline = @&quot;&amp;lt;span style=&amp;quot;text-decoration: underline;&amp;quot;&amp;gt;&quot;;
          string underlineReplacement = @&quot;&lt;span style=&quot;&quot;text-decoration:underline;&quot;&quot;&gt;&quot;;
          formattedEncodedText.Replace(underline, underlineReplacement);

          // &lt;/span&gt;
          // only find the spans that are related to the span for underlining
          var temp = formattedEncodedText.ToString();
          // for each instance of underline
          foreach (int i in temp.IndexOfAll(underlineReplacement))
          {
               // find the first instance of &lt;/span&gt; after the underline span and replace
               var index = temp.IndexOf(string.Format(htmlTag, @&quot;/span&quot;), i);

               // delete the string at that location
               temp = temp.Remove(index, string.Format(htmlTag, @&quot;/span&quot;).Length);

               // add in the new string at that location
               temp = temp.Insert(index, @&quot;&lt;/span&gt;&quot;);
          }

          formattedEncodedText = new StringBuilder(temp);

          // &lt;ul&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;ul&quot;), @&quot;&lt;ul&gt;&quot;);
          // &lt;/ul&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/ul&quot;), @&quot;&lt;/ul&gt;&quot;);

          // &lt;ol&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;ol&quot;), @&quot;&lt;ol&gt;&quot;);
          // &lt;/ol&gt;
          formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/ol&quot;), @&quot;&lt;/ol&gt;&quot;);

          // &lt;li&gt;
         formattedEncodedText.Replace(string.Format(htmlTag, @&quot;li&quot;), @&quot;&lt;li&gt;&quot;);
         // &lt;/li&gt;
         formattedEncodedText.Replace(string.Format(htmlTag, @&quot;/li&quot;), @&quot;&lt;/li&gt;&quot;);

         formattedEncodedText.Replace(@&quot;&amp;amp;nbsp;&quot;, @&quot;&amp;nbsp;&quot;);

         return formattedEncodedText.ToString();
     }
}

Shortening Open Id & Asp.net MVC

I’ve been working on a project that uses Open Id as the authentication method for public users.  I decided to use the DotNetOpenAuth provider to handle a lot of the grunt work for authentication.  The provider does a lot to simplify the process, but I wanted to make it shorter so I wrote a wrapper around the DotNetOpenAuth code.

You can find the example provided by DotNetOpenAuth for Asp.net MVC here. I am using version 3.4.1, so things may change but hopefully not in a newer version.

Requesting Authentication from OpenId Provider

To submit a request to authenticate all you need is the below code.  The first line builds a claims request to ask the Open Id provider for some pieces of information.  In my example below I am only asking for the user’s email address.  The second line handles making the request and redirecting the user to the provider for authentication.

var claimsRequest = OpenIdHelper.CreateClaimsRequest(OpenIdHelper.RequestInformation.Email);
returnOpenIdHelper.Login(openid_identifier, claimsRequest);

Validating Authentication from OpenId Provider

To validate a request is even easier,  the OpenIdHelper has a ValidateResponse function that will return true if the user is valid or false if not.  If the user is valid the oepnIdUser parameter will be populated with the user’s information.  If there was an error the message parameter will contain the error message to do with what you please.

Authentication.OpenIdUser openIdUser;
string message;

if (OpenIdHelper.ValidateResponse(out openIdUser, out message))
{
    // do some work
}

The below class is what is returned in the first parameter.

public class OpenIdUser
{
 /// <summary>
 /// Essentially the userid
 /// </summary>
 public string ClaimedIdentifier { get; set; }

 public DateTime? Birthdate { get; set; }
 public string Country { get; set; }
 public string Email { get; set; }
 public string FullName { get; set; }
 public string Gender { get; set; }
 public string Language { get; set; }
 public string Nickname { get; set; }
 public string PostalCode { get; set; }
 public string TimeZone { get; set; }
}

Putting it together I have the following actions in my account controller.

[AcceptPost]
 public ActionResult Authenticate(string openid_identifier)
 {
 var claimsRequest = OpenIdHelper.CreateClaimsRequest(OpenIdHelper.RequestInformation.Email);
 return OpenIdHelper.Login(openid_identifier, claimsRequest);
 }

 /// <summary>
 /// Response from OpenId provider telling is user is authentic or not
 /// </summary>
 /// <param name="returnUrl"></param>
 /// <returns></returns>
 [ValidateInput(false)]
 public ActionResult Authenticate()
 {
 Authentication.OpenIdUser openIdUser;
 string message;

 if (OpenIdHelper.ValidateResponse(out openIdUser, out message))
     {
          // do some work
     }
 }

My OpenIdHelper can be downloaded at http://gist.github.com/323195

OpenId Provider Selector

It’s really a matter of preference but I picked the OpenId Selector.  I chose it because it’s simple to use.


<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
 LogOn
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="HeaderContent"  runat="server">
 <link href="../../Content/openid.css" rel="stylesheet"  type="text/css" />
 <script src="../../Scripts/openid-jquery.js"  type="text/javascript"></script>
 <script type="text/javascript">
 $(document).ready(function() {
 openid.init('openid_identifier');
 });
 </script>
 </asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<!-- Simple OpenID Selector -->
<% using (Html.BeginForm("Authenticate", "Account", FormMethod.Post, new { @id = "openid_form" }))
 { %>

 <input type="hidden" name="action" value="verify" />

 <fieldset>
 <legend>Sign-in or Create New Account</legend>

 <div id="openid_choice">
 <p>Please click your account provider:</p>
 <div id="openid_btns"></div>
 </div>

 <div id="openid_input_area">
 <input id="openid_identifier" name="openid_identifier" type="text" value="http://" />
 <input id="openid_submit" type="submit" value="Sign-In"/>
 </div>
 <noscript>
 <p>OpenID is service that allows you to log-on to many different websites using a single indentity.
 Find out <a href="http://openid.net/what/">more about OpenID</a> and <a href="http://openid.net/get/">how to get an OpenID enabled account</a>.</p>
 </noscript>
 </fieldset>

<% } %>

</asp:Content>

It could just be me, but I had a strange problem with the plug-in and had to make a minor change to get it to function properly.  In the situation where I have previously selected an OpenId provider, the next time I come to the page and try to select a different provider it still goes to the original provider that was selected.

In the openid-jquery.js plug-in, I had to change line 169 in the setOpenIdUrl function from :

hidden.value = url;

to

$(hidden).val(url);

Well that’s all I got for my first post, hope it’s at least somewhat useful to someone other than me.  Any feedback or suggestions would be appreciated.

In the openid-jquery.js plug-in, I had to change line 169 in the setOpenIdUrl function from :