My Time As a Microsoft MVP

In the early 2000’s, I was working for a State agency in Pennsylvania in a .NET development role.  I’ve always been fascinated by programming on many levels: I really liked to learn the nuts and bolts of the framework, as well as the ability to create something – albeit digitally.  I tried to learn as much as I possibly could; I’d read tech books, read web sites, and post on forums.  I was pretty active specifically on the ASP.NET forums.

Sometime in 2007, I received an email from Microsoft in regards to the MVP program!  I was shocked when I got the email.  I spent a lot of time there, posting questions in hoping to gain insight and trying to provide answers to assist the technical community.  When the honor was confirmed, I was really appreciative of it; it was a great honor.

Fast forward 10 years later:

mvptenyears

I’ve been very blessed individual.  I’ve gotten to offer my time and skills to the community.  I’ve gotten to meet individuals at Code Camps or Give Camps.  I’ve gotten to write for DevProConnection Magazine, ASP Alliance, DotNetSlackers, DotNetJohn,  this blog, and other places.   I considered speaking for Pluralsight, but I’m not the greatest speaker.  Additionally, I’ve gotten to be involved in interesting projects over the years, as I shifted from government work to consulting work to product development.  I’ve gotten to help analyze and solve other people’s technical (and sometimes personal) problems.

Life really comes at you fast some times.  It doesn’t seem like long ago that our 3 children entered our world, but the facts remain the same (ages 11, 9, 7).  We adopted our beautiful daughter from China, and we are in the process of adopting our son (also from China).  My kids have been involved in school plays, baseball games, soccer practices and games, basketball games, holiday events, church activities, school events and more.  As my career progressed, my workload got bigger, my involvements became greater, and my stresses increased.  I burned out a few times along the way, my free time dwindled between work, an ever growing family, and general increased demands.

Ten years was my run as a Microsoft MVP.  I was informed that I will not be renewed.  Microsoft was great to me and gave me many opportunities during that ten years; I am forever grateful for that.

Advertisements

AJAX File Uploads with HTML 5

I see on StackOverflow the question often how to upload a file via AJAX.  It turns out it is actually not that difficult. We utilize a solution using the Html 5 FileReader component. The idea is have the file reader read a PDF file contents, and transfer those contents to a hidden field (stored in the $hidden variable). A portion of the script we use is shown below.

$("#FileUpload").on('change', function (e) {
var $self = this;
var file = $self.files[0];

var fileReader = new FileReader();
fileReader.addEventListener('load', function () {
   var result = fileReader.result;
   $hidden.val(result);
});
fileReader.readAsDataURL(file);

$self.val('');
});

Once a file is read, it invokes the “load” event with the contents of the file; the contents of the file are then stored in a hidden field. Since the contents are in the HTML file, it’s possible then to send those HTML contents to the server, or be a part of a normal postback lifecycle.

The idea with “readAsDataURL” is it creates a URL like the following: “data:text/html,sdafadf34533543sefkafdsadf90809as8dfasdf90asdf9fsdf” where the contents of the PDF are really large. You’ll need to extend what is acceptable as a part of your content.

On the server side, the solution is as simple as splitting the contents after the first comma like:

//Strip off the "data:text/html," portion of the data URL posted back to the server
fileContents.Substring(fileContents.IndexOf(",") + 1);

This is one of many solutions; there are a wide variety of JQuery or other solutions out there.

ASP.NET MVC And Client Side Lists with Kendo

In this post, I’m going to illustrate a very simple way to create client-side list-based UI’s in ASP.NET MVC. The idea with this example is to allow the ability to add a bulk number of list items that doesn’t require constantly posting back to add additional items. In this example, we’ll use Kendo UI Core framework templating capabilities, although any templating framework will do.

To start, let’s look at a very simple model:

public  class SystemTestModel
{
   public List Entities { get; set; }
}

public class SystemListEntity
{
   public string Name { get; set; }
   public string Value { get; set; }
   public bool IsDeleted { get; set; }
}

Here we have a View Model that has a list of child items. Very simple. Notice the entity has 2 properties, and an IsDeleted property, which will be illustrated later. For this example, the controller setup is simple; it reads the form posted values and rebuilds the non-deleted ones:

public ActionResult List()
{
   var model = new SystemTestModel { Entities = new List() };
   return View(model);
}

[HttpPost]
public ActionResult List(SystemTestModel model)
{
   //Remove non-deleted records - deleted from  client
   var entities = model.Entities.Where(i => i.IsDeleted == false);

   //Save entities to DB or other work
   //Reload UI
   return View(new SystemTestModel { Entities = entities.ToList() });
}

Within the view, the Name/Value pairs are rendered

<tbody id="Grid" data-last-index="@(Model.Entities.Count - 1)">
   @for (var i = 0; i < Model.Entities.Count; i++) {
     <tr>
         <td>
            <input type="text" name="@Html.NameFor(m => m.Entities[i].Name)" value="@Model.Entities[i].Name" />
            <input type="hidden" name="@Html.NameFor(m => m.Entities[i].IsDeleted)" value="@Model.Entities[i].IsDeleted" />
         </td>
         <td>
            <input type="text" name="@Html.NameFor(m => m.Entities[i].Value)" value="@Model.Entities[i].Value" />
         </td>
      </tr>
   }
</tbody>

Each server-side item is rendered using the collection-based naming syntax that MVC uses to identify collections. The name for a collection-based item looks like the server-side equivalent: Entities[X].[Field] (ie. Entities[0].Name). This is important because our client-side HTML template must do the same thing:


   <tr>
      <td>
          
          <input type="hidden" name="@Html.NameFor(m => m.Entities[-99].IsDeleted)" value="@Boolean.FalseString" />
      </td>
      <td>
          <input type="text" value="#= Value #" name="@Html.NameFor(m => m.Entities[-99].Value)" />
      </td>
   </tr>

Notice in the template the -99; the really neat thing about the NameFor helper is that the expression doesn’t need to be valid; -99 works and literally renders to the HTML as “Entities[-99].Name”. Notice that the script block is the same equivalent above, but will be used to render client-side additional elements. The HTML between the two doesn’t need to be exact, but similar. The view will use this template when the “Add” button is clicked.

What that really means is that the server may have rendered 2 name/value items, and the client can render additional pairs. Our approach is to ensure that we render the pairs in sequential order whether created from server or client, preserving that sequential order.

The view has an add button. The add button triggers the templating capability of kendo. The idea with the template is to get the HTML for the entry and replace the “-99” with the actual index. So if the server-side rendering produced 2 elements (using indexes 0 and 1), the client-side “Add” button generates items starting from index “2” and greater.

$(function () {
   //http://docs.telerik.com/kendo-ui/framework/templates/overview
   $("#NewButton").on("click", function (e) {
      var html = $("#ItemTemplate").html();
      //Get the last index, add 1 because we are adding an item at the new index
      var index = $("#Grid").data("last-index") + 1;
      $("#Grid").data("last-index", index);

      //Replace -99 with the new Index
      html = html.replace(/-99/g, index);

      //Can be used to apply data values from JS
      var template = kendo.template(html);
      var data = {}; //For now, not doing any template binding
      var content = template(data);
            
      $("#Grid").append(content);
   });
});

The first step here is get the templated HTML, and update the current index appropriately. When this UI posts back, the updated index sequence posts back the new items correctly at positions 2 and greater. When the UI reloads, we now have server-side items created from the new index, and new items can be added again.

You may have noticed the IsDeleted property; this can be used to indicate items as deleted. The UI can have a delete button, which can trigger JavaScript that can hide the entire TR tag of the item from view and update the hidden field. When posted back, a permanent delete can happen (purge from the DB if it was originally persisted).

The main goal of this approach is bulk entry of lists without having to postback to add each item, like web forms used to do.

Here is the entire View (assumes JQuery and Kendo scripts included):

@model SystemTestModel

<form action="" method="post">

   <div class="row">
      <div class="col-md-12">

         <table class="table table-bordered table-hover">
            <thead>
               <tr>
                  <th>Name
                  <th>Value
               </tr>
            </thead>
            <tbody id="Grid">
               @for (var i = 0; i < Model.Entities.Length; i++)
               {
                    <tr>
                      <td>
                         <input type="text" name="@Html.NameFor(m => m.Entities[i].Name)" value="@Model.Entities[i].Name" />
                          <input type="hidden" name="@Html.NameFor(m => m.Entities[i].IsDeleted)" value="@Model.Entities[i].IsDeleted" />
                        </td>
                         <td>
                             <input type="text" name="@Html.NameFor(m => m.Entities[i].Value)" value="@Model.Entities[i].Value" />
                           </td>
                          </tr>

               }
            </tbody>
         </table>

      </div>
   

   <div class="row">
      <div class="col-md-12">

         <button type="submit" name="Action" value="SAVE" class="btn btn-primary">
             Save 
         </button>
         <button type="button" name="Action" value="NEW" class="btn btn-default">
             New
         </button>

      </div>
   </div>

</form>

@section scripts {
   
      <script type="text/x-kendo-template">
               <tr>
                    <td>
                        <input type="text" value="#= Name #" name="@Html.NameFor(m => m.Entities[-99].Name)" />
                        <input type="hidden" name="@Html.NameFor(m => m.Entities[-99].IsDeleted)" value="@Boolean.FalseString" />
                    </td>
                     <td>
                        <input type="text" value="#= Value #" name="@Html.NameFor(m => m.Entities[-99].Value)" />
                     </td>
              </tr>
      </script>

<script type="text/javascript">
      $(function () {

         //http://docs.telerik.com/kendo-ui/framework/templates/overview
         $("#NewButton").on("click", function (e) {
            var html = $("#ItemTemplate").html();
            //Get the last index, add 1 because we are adding an item at the new index
            var index = $("#Grid").data("last-index") + 1;
            $("#Grid").data("last-index", index);

            //Replace -99 with the new Index
            html = html.replace(/-99/g, index);

            //Can be used to apply data values from JS
            var template = kendo.template(html);
            var data = {}; //For now, not doing any template binding
            var content = template(data);
            
            $("#Grid").append(content);
         });

      });
   </script>

}

And Controller:

public class SystemListEntity
   {
      public string Name { get; set; }

      public string Value { get; set; }

      public bool IsDeleted { get; set; }

   }


    public class SystemController : BaseController
    {

         public ActionResult List()
         {
            var model = new SystemTestModel { 
                          Entities = new List<SystemListEntity>() };

            return View(model);
         }

         [HttpPost]
         public ActionResult List(SystemTestModel model)
         {
            var entities = model.Entities.Where(i => i.IsDeleted == false);

            //Save entities

            //Reload UI
            return View(new SystemTestModel { Entities = entities.ToList() });
         }
}

Adding Security To Html Helpers

I know the new MVC 5 HTML tag attributes for rendering ASP.NET widgets is all the rage, but there are a lot of useful approaches to using the server-side HTML helpers.  One simple extension method we are going to look at is adding control level security.  Often within our applications, we have a means of providing UI security at the control level.  We may, for instance, hide a control if the user doesn’t belong to a certain role.  It’s really simple to add this as an extension to IHtmlString, which is what HTML tag helpers do.  First, let’s look at how this might be used:

@Html.TextBoxFor(i => i.AccountID).IfInRole("ADMIN")

Notice how our textbox has an IsVisible method; this checks if the user is in the ADMIN role, and if so, it does the following:

public static IHtmlString IfInRole(this IHtmlString html, string role)
{
    if (HttpContext.Current == null)
       return html;

    if (HttpContext.Current.User.IsInRole(role);
       return html;
    else
       return new MvcHtmlString("");
}

In this method, if the user doesn’t have permissions, it outputs a blank string instead of the original HTML, thus providing some level of control security. We could use claims to do this, or some other security feature; it really doesn’t matter what is used behind the scenes. Also, we could also provide some default template to use if the control is hidden, as a blank space may not be optimal. This can especially be the case if you are using Twitter Bootstrap, because your form may look like:

Account @Html.TextBoxFor(i => i.AccountID, new { @class = "form-control" })

And thus a wrapper around it like:

@if (Html.IsInRole("Admin")) {
  
..
}

Or using a lambda template might be better. When there is supporting HTML wrapping the HTML Helper, showing or hiding may be a little more complicated depending on your design. I hope you see from this simple example how you can add some security features into your application using the old-school HTML helpers.

Kendo UI Core and DropDownListFor

Kendo UI Core supports data attribute initialization of its widgets. This initialization approach is largely created for it’s MVVM capabilities, but also can be used for server-side approaches too, which in turn can be used with ASP.NET MVC HTML helpers. The setup may be a little different than you are used to.

Please note: Although Telerik has MVC wrappers already created and ready for you to develop with, these come with the licensed version of the product and are not available through the Kendo UI Core license.

To begin, let’s look at how we’d setup the dropdownlist as an HTML widget without and use of the server.

<select id="reasonID" data-role="dropdownlist" data-option-label="-Select Reason-" data-value="">
  <option selected="selected" value="">-Select Reason-
  <option value="1">Entered in Error
  <option value="2">Removed
</select>

In our example, a select element with a pre-defined list of options is wrapped with the kendo dropdownlist widget. It’s initialized via the data-role attribute, indicating it’s a dropdownlist widget. Next, it defines options that the widget supports. Most of the attributes on the widget that you would configure through the JavaScript API can be defined here, but the syntax differs sometimes (for instance, the optionLabel property you would use in JS initialization is data-option-label in data attribute initialization). If you run into an issue, I was able to find what I needed online so far.

Telerik has some documentation on data attribute initialization here.

The dropdownlist widget can use a textbox as the source, and can also wire data up using JSON via local JavaScript API of via AJAX if you like. I’ve stuck with a select because I’m using the MVC DropDownListFor widget, and to get this widget to render the correct content that I needed, I had to use the following configuration:

@Html.DropDownListFor(
      i => i.ReasonTypeID,      
      Model.ReasonTypes, 
      new
      {
           data_role="dropdownlist", 
           data_option_label="-Select Reason-", 
           data_value=(Model.Receiving.ShrinkTransactionTypeID.HasValue ? Model.Receiving.ShrinkTransactionTypeID.Value.ToString() : ""), 
           style="width:100%;" })

Most of this is standard. The third parameter of DropDownListFor provides HTML attributes to the rendered select option. Here we define the role data attribute used for initialization. The next attribute defines the option label, and the data_value attribute defines the selected value, which is interesting. We already define what’s selected via the lambda expression pointing to our model. However, that’s used to render the selected attribute. What I found is that to cover all selection scenarios (including the default “Select Something” item) is to add the value attribute too, which the widget uses to perform the selection. The code above manually checks for null and converts to an empty string if no value present.

In case you didn’t notice, note how the HTML attribute use data_role, particularly the underscore. The convention that MVC uses is underscore (supported by the language), which is converted to a dash during the rendering process.

Discussing ASP.NET MVC Model Binding With Hidden Data

If you have taken over an MVC application, you may have come across a dilemma like the following. Notice that in a view, within a form, you’ll see a group of hidden fields mixed in with a form like the following.

Html.HiddenFor(i => i.ContactID)
Html.HiddenFor(i => i.ContactTypeID)
Html.HiddenFor(i => i.ContactDescription)
Html.HiddenFor(i => i.ContactTypeDescription)
Html.HiddenFor(i => i.OrganizationID)

Html.LabelFor(i => i.OrganizationName, new { @class = "control-label" }) Html.TextBoxFor(i => i.OrganizationName, new { @class = "form-control" })
@* and so on *@

My example had five hidden fields, but I’ve seen a lot more. These fields are not useful to the form per se; the user doesn’t enter them. However, the information is important to the records about to be updated in the database, and thus are included in the form as hidden fields for that reason. However, another reason is it acts as a quasi-ViewState mechanism that makes it very easy to replenish the following model:

public class ContactInfoModel
{
    public int? ContactID { get; set; }

    public int? ContactTypeID { get; set; }

    public string ContactDescription { get; set; }

    public string ContactTypeDescription { get; set; }

    public int? OrganizationID { get; set; }

    public string OrganizationName { get; set; }

    /* and so on */
}

[HttpPost]
public ActionResult Contact(ContactInfoModel model)
{
 ...
}

While OrganizationName and the other unlisted properties came from the form, the first five properties (and potentially more) are stored in the hidden field. The hidden field makes it nice and easy to replenish this model, and than allow the developer to use the parameters in the post action. MVC does a very nice job posting the values back to the server and populating these properties.

However, notice I said before, that this was a ViewState-like solution? It’s not quite within the model of ViewState because all of the parameters are embedded in the form in clear text. In most systems, the user is required to login before they can ever get to a page that contains this type of information. Either way, the users have the tools (IE developer tools, Firebug) to inspect and change the values in the hidden fields if they so desired. That is where the danger can lie.

Here’s the other side of the conundrum: if we don’t reload the parameters, what do we do? If we didn’t include the hidden fields, the first five parameters are not loaded from the client and thus the model is partially replenished. In most cases, these pieces of information might not be needed anyway (with the exception of OrganizationID in our scenario).

The application can certainly requery the information it needs, but then the information gets reloaded on every postback, which can get more expensive. The application could also use Session to store the information fields too.

I’m not saying “NEVER use hidden fields”, but I’m debating the value of a large number of hidden fields for replenishing the model. I probably fit within the category of storing any relative information in Session or requerying the information from the database, depending on how much information we are talking about. What is your thoughts or preference? Using hidden fields, session, database?

Using Interfaces for ASP.NET MVC Model Binding

Sometimes you may want to support view reuse, where a partial view displays a portion of the application in a reusable fashion. Suppose you had the following entity which has a bunch of properties.

public class Customer
{
   public int CustomerID { get; set; }

   public string FirstName { get; set; }

   public string LastName { get; set; }

   public string AccountNumber { get; set; }

   .
   .
}

Suppose you wanted to use a PartialView because it was an AJAX widget with a JavaScript initialization script, and defining a reusable control made it really easy to support this. MVC defines a strongly typed model reference, so does that mean we have to bind the model directly to Customer, or define a custom type for an editor template?

We actually can use interfaces by adding the following:

public interface IAccountEntity
{
   string AccountNumber { get; set; }
}

We can define this in a partial view:

@model IAccountEntity

@Html.TextBoxFor(i => i.AccountNumber)

   $(function() {
      /* Registration Script */
   });

And then use it in our EditCustomer view, as a partial with the existing model:

@Html.Partial("EditAccountNumber", Model)

Since Model (of type Customer) is also IAccountEntity, this translates just fine with MVC. It works just as well when you use hierarchies too. For instance, Customer implements IAccountEntity, but what if we had a CustomerModel class above Customer like:

CustomerModel
     Customer : IAccountEntity
        AccountNumber

If EditCustomer view looks like the following:

@model CustomerModel
.
.

<div class="form-group">
   <label class="col-md-2 control-label">First Name</label>
   <div class="col-md-10">
       @Html.TextBoxFor(Function(i) i.Customer.FirstName)
   </div>
</div>
<div class="form-group">
   <label class="col-md-2 control-label">Last Name</label>
   <div class="col-md-10">
       @Html.TextBoxFor(Function(i) i.Customer.LastName)
   </div>
</div>
<div class="form-group">
   <label class="col-md-2 control-label">AccountNumber</label>
   <div class="col-md-10">
       @Html.Partial("EditAccountNumber", Model)
   </div>
</div>

Notice how the model is passed in directly; this won’t work for our scenario, because the EditAccountNumber expects an IAccountEntity, and requires that the partial be passed in this way:

@Html.Partial("EditAccountNumber", Model.Customer)

However, that doesn’t work for our needs, if our controller has a post operation of the following:

[HttpPost]
ActionResult Edit(CustomerModel model)
{
    if (string.IsNullOrEmpty(model.AccountNumber))
    {
      //This will always be the case, why?  See below
    }
}

Welcome to one of the challenges of MVC model binding. In the previous form, the first/last name and account number would post back to the server something like:

Customer__FirstName: BOB
Customer__LastName: SMITH
AccountNumber: ABC123

What needs to happen is the “AccountNumber” key also needs to be Customer__AccountNumber for it to successfully bind back to the server. You can add AccountNumber as a parameter to the post method, or we can add another interface that supports our hierarchy, and add this interface to the CustomerModel:

//Interface definition
public interface IAccountNumberModel
{
    IAccountNumberEntity Customer { get; set; }
}

//Update to the model class
public class CustomerModel : IAccountNumberModel
{

   public Customer Customer { get; set; }

   IAccountNumberEntity IAccountNumberModel.Customer { get; set; }

}

Here IAccountNumberModel has the same property name as CustomerModel; that’s important to make sure the model binding name structure matches. Now we can pass in the CustomerModel to the EditAccountNumber view with these modifications:

//EditAccountNumber
@model IAccountNumberModel

@Html.TextBoxFor(i => i.Customer.AccountNumber)
.
.

//EditCustomer:
.
.
@Html.Partial("EditAccountNumber", Model)

Since CustomerModel implements IAccountNumberModel, and this matches the type of model on our partial view, everything binds correctly.

ASP.NET MVC Seamless Routing Encryption

There are certain pages in the application where the data passed in must be encrypted in a GET request. This could be a link redirection from an email or another site, or just an internal redirect where the parameters can’t get exposed. A link like this may actually look like:

/Some/Action?enc=345SFIPOWHG:LNNJE:LKJWET46-DSFSF:KJ

The data is nonsensical to the user, but contains identifying information about the user. For instance, the encrypted data may have the following information:

– User ID
– Response Identifier
– Response (Yes/No, Agree/Disagree, text description, whatever else)

The system can then check that the user logged in matches the user in the URL request. It can lookup the associated response database record, and record the response provided. This feature is not native to ASP.NET MVC, but is relative easy to build in. This post will illustrate how to do so, using the following steps:

1) The first step is to create an action method to define a URL. We’ll want to create two forms: one method as a redirection, and one method as an URL generation. Both of these will be extension methods on different objects:

private static string GetEncryptedData(object args)
{
    var encryption = new EncryptionService();
    var list = new RouteValueDictionary(args);
    var items = new List();

    foreach (var entry in list)
    {
         items.Add(entry.Key + "=" + (!string.IsNullOrEmpty(entry.Value) ? entry.Value : ""));
    }

    return encryption.Encrypt(String.Join("&", items));
}

public static ActionResult RedirectToActionSecure(this ControllerBase controller,
                                                  string action, 
                                                  string controller, 
                                                  object args)
{
    var encText = GetEncryptedData(args);
    return controller.RedirectToAction(action, controller, new { enc = encText });
}

public static IHtmlString ActionSecure(this UrlHelper url, 
                                       string action, 
                                       string controller, 
                                       object args)
{
    var encText = GetEncryptedData(args);
    return url.Action(action, controller, new { enc = encText });
}

Certainly, you can create overloads without the action and/or controller too, which is easy to do. Additionally, this code should do more null checking; it assumes that the data exists. The first step is get a reference to the encryption service you are using for your application. I’m leaving that out of this post. Using this service, a querystring is generated and then encrypted together. The value is stored in the “enc” querystring value when routed. This looks like in the code:

public ActionResult X()
{
   return RedirectToActionSecure("Action", "ctlr", new { a = 1, b = 2 });
}

Or in the view:

@Url.ActionSecure("Action", "ctlr", new { a = 1, b = 2 });

When a request is made to that controller and action, MVC checks for the “enc” querystring parameter. It does this in an Action filter attribute, on ActionExecuting.

public class EncryptionActionAttribute : ActionFilterAttribute
{
   public override void OnActionExecuting(ActionExecutingContext context)
   {
        var encryption = new EncryptionService();

       // Step 1: parse the URL
       var url = context.HttpContext.Request.Url.ToString();
       var index = url.IndexOf("enc=");

       if (index > 0) {
         //Get the encrypted value and decrypt it.
         var encText = context.HttpContext.Server.Decode(url.Substring(index + 4));
         var groups = encryption.Decrypt(encText).Split('&');
         var actionParams = filterContext.ActionDescriptor.GetParameters();

         //Parse all of the "KEY=VALUE" groups
         foreach (var group in groups)
         {
            var pair = group.Split('=');

               if (pair.Value == null)
                 continue;

               //Make sure the action has the parameter of the given name
               var actionParam = actionParams.FirstOrDefault(i => i.Name == pair.Key);
               if (actionParam != null) {
                  var nullType = Nullable.GetUnderlyingType(actionParam.ParameterType);

                  //If a nullable type, make sure to use changetype for that type instead; 
                  //nullable types are not supported
                  if (nullType != null)
                     context.ActionParameters[pair.Key] = 
                          Convert.ChangeType(pair.Value, nullType);
                  //Otherwise, assign and cast the value accordingly
                  else
                     context.ActionParameters[pair.Key] = 
                          Convert.ChangeType(pair.Value, actionParam.ParameterType);

               }

         }
       }
   }
}

There’s a lot to it, so let’s break it down:

– Again, missing null checks and conversion error recovery, so you’ll want to ensure that’s there.
– The first step is to grab the encrypted value from the URL and decode it; once we have this value, the encrypted value is decrypted to get the key/value pairs.
– The filter context has two parameter types: ActionDescription, which GetParameters() returns the metadata of the action method, and ActionParameters, which is a collection of values about to be injected into the action. The ActionParameters collection can be added or modified as you like.
– Each key/value pair is evaluated, and injected into the ActionParameters collection; the values that were encrypted were injected in.
– We first have to check that a nullable type is converted correctly; otherwise, the cast to a nullable type through ChangeType raises an exception.

Some/Action?enc=23442q5wetew

It’s decrypted to:

UserID: 1
ResponseID: 3
Response: YES

The values are inserted into an action method like this: