In my ASP.NET MVC app, I want to encrypt the route data and NOT QueryString, in other word:
I\'m using the ASP.NET MVC default route pattern :
rou
I found a nice guide to do what I want but with QueryString BUT NOT Route Data, So I updated it to work with both QueryString and Route Data, the guide was based on creating custom Helper and custom Attribute, so put my changes easily, I will mention by code my changes:
Custom Helper
public static MvcHtmlString EncodedActionLink(this HtmlHelper htmlHelper, string linkText, string Action, string ControllerName, string Area, object routeValues, object htmlAttributes)
{
string queryString = string.Empty;
string htmlAttributesString = string.Empty;
//My Changes
bool IsRoute = false;
if (routeValues != null)
{
RouteValueDictionary d = new RouteValueDictionary(routeValues);
for (int i = 0; i < d.Keys.Count; i++)
{
//My Changes
if (!d.Keys.Contains("IsRoute"))
{
if (i > 0)
{
queryString += "?";
}
queryString += d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
}
else
{
//My Changes
if (!d.Keys.ElementAt(i).Contains("IsRoute"))
{
queryString += d.Values.ElementAt(i);
IsRoute = true;
}
}
}
}
if (htmlAttributes != null)
{
RouteValueDictionary d = new RouteValueDictionary(htmlAttributes);
for (int i = 0; i < d.Keys.Count; i++)
{
htmlAttributesString += " " + d.Keys.ElementAt(i) + "=" + d.Values.ElementAt(i);
}
}
StringBuilder ancor = new StringBuilder();
ancor.Append("<a ");
if (htmlAttributesString != string.Empty)
{
ancor.Append(htmlAttributesString);
}
ancor.Append(" href='");
if (Area != string.Empty)
{
ancor.Append("/" + Area);
}
if (ControllerName != string.Empty)
{
ancor.Append("/" + ControllerName);
}
if (Action != "Index")
{
ancor.Append("/" + Action);
}
//My Changes
if (queryString != string.Empty)
{
if (IsRoute == false)
ancor.Append("?q=" + Encrypt(queryString));
else
ancor.Append("/" + Encrypt(queryString));
}
ancor.Append("'");
ancor.Append(">");
ancor.Append(linkText);
ancor.Append("</a>");
return new MvcHtmlString(ancor.ToString());
}
Custom Attribute:
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
int Id;
Dictionary<string, object> decryptedParameters = new Dictionary<string, object>();
if (HttpContext.Current.Request.QueryString.Get("q") != null)
{
string encryptedQueryString = HttpContext.Current.Request.QueryString.Get("q");
//string decrptedString = Decrypt(encryptedQueryString.ToString());
string decrptedString = Decrypt(encryptedQueryString.ToString());
string[] paramsArrs = decrptedString.Split('?');
for (int i = 0; i < paramsArrs.Length; i++)
{
string[] paramArr = paramsArrs[i].Split('=');
decryptedParameters.Add(paramArr[0], Convert.ToInt32(paramArr[1]));
}
}
else if (!HttpContext.Current.Request.Url.ToString().Contains("?"))
{
//if (int.TryParse(Decrypt(HttpContext.Current.Request.Url.ToString().Split('/').Last()), out Id))
if (int.TryParse(Decrypt(HttpContext.Current.Request.Url.ToString().Split('/').Last()), out Id))
{
string id = Id.ToString();
decryptedParameters.Add("id", id);
}
}
else if (HttpContext.Current.Request.Url.ToString().Contains("?"))
{
//if (int.TryParse(Decrypt(HttpContext.Current.Request.Url.ToString().Split('/').Last().Split('?')[0]), out Id))
if (int.TryParse(Decrypt(HttpContext.Current.Request.Url.ToString().Split('/').Last().Split('?')[0]), out Id))
{
string id = Id.ToString();
if (id.Contains('?'))
{
id = id.Split('?')[0];
}
decryptedParameters.Add("id", id);
}
string[] paramsArrs = HttpContext.Current.Request.Url.ToString().Split('/').Last().Split('?');
for (int i = 1; i < paramsArrs.Length; i++)
{
string[] paramArr = paramsArrs[i].Split('=');
decryptedParameters.Add(paramArr[0], Convert.ToInt32(paramArr[1]));
}
}
for (int i = 0; i < decryptedParameters.Count; i++)
{
filterContext.ActionParameters[decryptedParameters.Keys.ElementAt(i)] = decryptedParameters.Values.ElementAt(i);
}
base.OnActionExecuting(filterContext);
}
Actually My changes was not that big, so the creadit actually for this guide.
You can use a custom model binder for this parameter
// /Controller/Example/0000000A
public ActionResult Example([ModelBinder(typeof(EncryptDataBinder))]int id)
{
return View(id);
}
The model binder
public class EncryptDataBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(int))
{
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult != null)
{
// Use your own logic here
bytes = ConvertUtilities.ToBytesFromHexa((string)valueProviderResult.RawValue);
return BitConverter.ToInt32(bytes, 0);
}
}
return base.BindModel(controllerContext, bindingContext);
}
}