react-social-login

The easiest way to integrate Social Login in your React Apps ...Checkout NPM
Showing posts with label MVC. Show all posts
Showing posts with label MVC. Show all posts

Saturday, February 9, 2013

Refactoring ASP.NET MVC Routes

Routing is vital to MVC. Routing defines mappings between URL and ActionMethod - that would handle request to that URL. For example, following route mapping defines that when a user hits "http://mysite/shopping/cart", call OrderController's ShowCart() method to handle this request.

routes.MapRoute("cart", "shopping/cart", new { controller = "Order", action = "ShowCart" });

Placing Routes

A common place to put route mappings is in  RegisterGlobalFilters method inside Global.asax:
 
public class MvcApplication : System.Web.HttpApplication
{
  public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  {
     //Define Routes
      routes.MapRoute(
          "Default", // Route name
          "{controller}/{action}/{id}", // URL with parameters
          new { controller = "Login", action = "Index", id = UrlParameter.Optional } // Parameter defaults
      );
  }
}
Often, you would use generic route "Controller/Action/Parameters" (as in aforesaid code) which maps Controller/Action/parameter with URLs tightly. But I prefer to explicitly define all routes (or at least as many as possible) to decouple URL with their handler methods for several reasons listed below:
  1. No matter how good your architecture is, you would find a need to re-factor it, when it grows. With Routes tightly mapped to methods, you may find difficulty in re-factoring. (without altering URLs)
  2. You may find a need to change routes for indexing purpose on search-engines or for any other reason as demanded by business people (without altering actions)
  3. In a complex scenario, you may wish to provide options to marketing team to be able to change routes and define a mechanism to map it with methods (without altering actions)
  4. You may wish to change URL which is attacked (without altering actions)
  5. Or any other reason for which you wish to alter either of URL or Method without altering other

Said that "Routes should be defined explicitly", over a period of time your routes may grow significantly. It would be wise to re-factor and organize your routes such that they are manageable and in some way logically grouped so that it's pretty easy to locate a Route.

This post is all about one such approach to organize your Routes.

Friday, December 7, 2012

Exporting events to google calendar Link HtmlHelper


Following is a ASP.NET MVC HtmlHelper to generate an anchor link for exporting an event to Google Calendar.
public static MvcHtmlString ExportEventToGoogleLink(this HtmlHelper htmlHelper, string title, DateTime startDateTime, DateTime endDateTime, string description, string location, string linkText, IDictionary<string, object> htmlAttributes = null)
        {
            const string dateFormat = "yyyyMMddTHHmmssZ";
            Uri url = System.Web.HttpContext.Current.Request.Url;
            StringBuilder sb = new StringBuilder();
            sb.Append("http://www.google.com/calendar/event?action=TEMPLATE");
            sb.Append("&text=" + title);
            sb.Append("&dates=" + startDateTime.ToUniversalTime().ToString(dateFormat));
            sb.Append("/");
            sb.Append(endDateTime.ToUniversalTime().ToString(dateFormat));
            sb.Append("&details=" + description);
            sb.Append("&location=" + location);
            sb.Append("&trp=false");
            sb.Append("&sprop=" + url.Scheme + "://" + url.Host);
            sb.Append("&sprop=name:" + url.Host);
            
            TagBuilder tagBuilder = new TagBuilder("a");
            tagBuilder.MergeAttribute("href", sb.ToString());
            tagBuilder.MergeAttribute("target", "_blank");
            tagBuilder.InnerHtml = "<span class='event-export-google'>" + linkText + "</span>";
            if (htmlAttributes != null)
                tagBuilder.MergeAttributes(htmlAttributes, true);
            return MvcHtmlString.Create(tagBuilder.ToString());
        }


Demo Link

Saturday, October 13, 2012

Conditionally render MVC layout section

Error:

The following sections have been defined but have not been rendered for the layout page "~/_SiteLayout.cshtml"


Reason:
Let's say there is a Layout as following:

<html>
<head>
</head>
<body>
 @RenderBody() 
 @RenderSection("footer")
</body>
</html>

And a view as following:
<H1>Hello World</H1>
@section footer{ Copyright 2012 }
When rendered,
<h1>Hello World</h1> will be rendered by RenderBody() while Copyright 2012 will be rendered by RenderSection(). But, what if for some reason you want to display footer conditionally on Layout? So for that, if you do something like following, you will encounter an error:

<body>
 @RenderBody() 
 if(condition){
 @RenderSection("footer")
 }
</body>

Reason is that MVC needs to flush out section declared in your view. Else it displays error as on top of article. To resolve this, there is a quick trick:
<body>
 @RenderBody() 
 if(condition){
 @RenderSection("footer") //display
 }
 else
 {
 @RenderSection("footer").ToString().Remove(0) //hide
 }
</body>

Saturday, June 23, 2012

Managing raw HTML and Razor code in project


Intent of this post
=================
This article is about approach for structuring MVC application so as to manage front end  raw HTML design code along with developer's corresponding dynamic razor code


Background
==================
In general,  following is a flow of an idea to a live page (from design perspective):


Now here comes a question: 
"How should static HTML code and dynamic Razor code be managed in a solution?"


Answer...Depends.......!
Case-1: When developer is the same person who does both front end design and server code, there is no special arrangement required and one physical .cshtml file is enough. 


Case-2: When designers are smart enough to sneak into developer's razor code and implement any UI requirement, again a single file is sufficient.


Case-3: In bigger projects, where exists separate team for Design+HTML code and Razor+Backend code which is bridged by a Manager, there, it is really a good idea to have design HTML exists physically separate from file which a developer works on.


Picking up Case-3, an ideal structuring would  be one which satisfies following:



  1. Shouldn't be complex for designers to add their raw HTML files
  2. Dynamic Page URL and it corresponding raw HTML design URLs should be relative so that they can be easily toggled in browser
  3. Raw HTML code and dynamic code should be physically separate so that both has their own repository version
  4. Raw HTML code shouldn't go to production. Only its dynamic code variant should!



An Approach
=====================
Following is an approach that I've found useful:
1. Create a separate area for design files. 
2. Create a default controller action that returns view passed in as argument to action
3. Create a custom config entry (say "KeepDesignFiles") and remove physical files based on this parameters. With this, different environments can explicitly specify need to have (or not have) design files.


Illustration
====================
As a example, let's say business people think of 2 live pages
1. http://www.mysite.com/theDate, which would displays current date
2. http://www.mysite.com/theDate/Tomorrow, which would display next day date


Then, as per our approach, the static design URLs should be


1. http://www.mysite.com/design/theDate, which would displays current date
2. http:// www.mysite.com /design/theDate/Tomorrow, which would display next date


Let's build it up!



1. Ctrl+Shift+N and create a new ASP.NET MVC 3 Web Application (I chose DesignManagementDemo as application name)
2. Select Empty Template and choose Razor as View Engine
Visual Studio will create folder structure but without any controller/view file
3. Right-Click project and select Add>Area. Give area "Design" as name


So far we've just added a new project and added a area called "Design". Now comes some customization.
4. Right Click Design>Contoller folder and add a new Controller (call HomeController)
5. Modify default Index action method as following:



public ActionResult Index(string viewName)
        {
            return View(viewName);
        }


Notes: We do not want to create separate action for each new view. Rather this scheme makes design framework generic and all what designer needs to do is add views file and need not worry about controllers/actions internals.

4. Right-Click Views folder and add a new folder called "Home"

5. Add a new View to this new folder called "TheDate"
Steps 4,5 create a new file Index.cshtml at Areas>Design>Views>Home>TheDate.cshtml

6. Put some content in this file. Like: This is a static page 20-June-2012

Imagine this is static HTML added by designer.
Compile and run your project. The page you've just added can be browsed using:
http://localhost:58429/design/home?viewname=thedate (Port number will likely differ)
Now, that's generic. But let's improve a bit by removing the need to specify viewname like this. 

7. Open Areas>Design>DesignAreaRegistration.cs and alter code as below:




 public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Design_default",
                "Design/{viewName}",
                new { controller="Home", action = "Index", viewName = "TheDate" }
            );
        }



Notes: We have hidden the need to explicitly set Home/Index in URL and set them as default within route definition. Now the same URL can be accessed as: 
http://localhost:58429/design/TheDate (exactly what we wanted)


At this point take a break and think on what if this solution is sent to a designer with only one instruction "Add all design files inside Areas>Design>Home by adding a view".

Let's see how does that please a designer?


Imagine business want a new URL http://localhost:58429/design/TheYear (which eventually has to display  current year). All designer need to do is:
a. Right Click on Home Folder
b. Add View called "TheYear"
c. Write their static HTML content. That's it!

Continuing with our example, where we need another URL to display next date, designer would follow following steps:
a. Right Click Home folder
b. Add a folder TheDate
c. Add a view called "TomorrowsDate"
d. Write static HTML content. Thats it!


It's now so easy for designer to add their design files with static HTML without worrying about internals and moreover the URLs go so well with actual need by just prefixing "Design".


Developers can now create their dynamic views by copying content from static HTML files and replacing them with dynamic code.


Above arrangement, helps us meet 3/4 objectives:

  • Shouldn't be complex for designers to add their raw HTML files
  • Dynamic Page URL and it corresponding raw HTML design URLs should be relative so that they can be easily toggled in browser
  • Raw HTML code and dynamic code should be physically separate so that both has their own repository version



We've one more objective to meet: Raw HTML code shouldn't go to production. Only its dynamic code variant should!


In a nutshell, I would create a custom config key in Web.Config called "KeepDesignFiles" with value true/false. If false, application will physically delete the Design folder otherwise do nothing. So in production all I need to do is just set this property as true.


For an illustration, In your web.config add:

<appSettings>
    ...
    <add key="KeepDesignFiles" value="false" />
appSettings>



We'll use PreApplicationStartMethod to read this config and delete design folder even before Application_Start is called.
In AssemblyInfo.cs 



[assemblyPreApplicationStartMethod(typeof(DesignManagementDemo.PublishDesignFilesConfiguration), "Start")]

In this code, we tell .NET to call Start method of file called PublishDesignFileCOnfiguration


Code of class and method registered in AssemblyInfo.cs:



using System.Configuration;
using System.Linq;
using System.IO;
using System.Reflection;
namespace DesignManagementDemo
{
    public static  class PublishDesignFilesConfiguration
    {
        public  static void  Start()
        {
            var appsettings = ConfigurationManager.AppSettings["KeepDesignFiles"];
            bool keepDesignFiles = bool.Parse(appsettings);
 
            if (!keepDesignFiles)
            {
                var dir =
                    Directory.GetParent(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///""")).Parent.
                        GetDirectories("Areas/Design");
                if(dir.Any())
                    dir[0].Delete(true);
            }
        }
    }
}



Above code is called automatically once even before application_start event is called. It reads config and sees if KeepDesignFiles is true/false? If false, it deletes the Design folder. I find this approach better as you can always put more customized logic and configuration keys for this purpose and the best thing is application itself tells whether it should or shouldn't have design. Above code is good for local test but definitely you would write better code in production :)


Hope this post is of help. I encourage to post any different approach as there is always scope of improvement to everything.


 Cheers!

Wednesday, March 28, 2012

Solving Potentially dangerous Request.Form with custom attribute in MVC3


If you punch in “<” character while filling a MVC web form (or even ASP.NET) and press submit, you’ll encounter a System.Web.HttpRequestValidationException exception. I.e.,
form
results in:
error
Upon search, you’ll find few common options to resolve this. I've tried to consolidate them and also have added an interesting approach at end which I find very useful for handling this issue:

Option-1: Disabling RequestValidation through Web.Config
Adding following tag in Web.Config:



  
     
  



Pros: Easiest to do!!
Cons: Skips validation throughout application. As a good rule, Validation should be explicitly bypassed but by setting this option, we are implicitly bypassing validation which is not good.


Option-2: ValidateInput attribute
Another option that resolves this problem is using ValidationInput = false attribute on Controller. For example:
[ValidateInput(false)]
[HttpPost]
public ActionResult Index(MyViewModel vModel)
{
    return View();
}
Pros: Easy to use and can be applied only on specific controllers
Cons: Once applied to a controller, all values posted from form for this controller skip validation. Also, it is tedious when you are specifically trying to bypass form values for a model used in many controllers.

Option-3: AllowHTML
Using AllowHTML tag on Model field. For example, if our Model used to render form was:
public class UserModel
{
      public string FirstName { get; set; }
}

Only change that needs to be done is adding AllowHTML attribute over FirstName.
[AllowHtml]
public string FirstName { get; set; }

Pros: Firstly it can be applied to a specific property (instead skipping validation at controller or application level). Secondly it is easy to use and also removes code redundancy as this attribute needs to be applied only once (over the property).
Cons:Problem with this approach becomes evident, when you plan to display content in raw format on a view. For example, if you set [AllowHTML] and then enter “<script>alert(1)</script>” as input value, there will be no error on form submission. :
< @Model.UserName will display <script>alert(1)</script> as it is. This is good on part of MVC that be default it is encoding HTML content before display.

But what, if you want to display HTML, as it is (may be because it is a rich text entry)?

If you instead use following code:

@Html.Raw(Model.UserName), and pass same input, you will see an alert because browser would execute the script.

alert

This is of course dangerous!!
You can resolve this issue by adding a regular expression validation too which checks for <script> tag in content. However this need to know regular expressions (I found less people comfortable in RegEx) and also bad from maintenance perspective as if there is a need tomorrow to disallow one more tag besides <script>, this would require updating of all fields having combo of AllowHTML and RegularExpression.
A much better approach is one which:


  • Allows HTML content

  • Can be customized to specify tags allowed

  • Is as easy to use and granular at property level like AllowHTML

  • Easy to maintain

One option that nicely fulfills above conditions is creating a custom attribute.


[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
    sealed class RichHTML : ValidationAttribute, IMetadataAware
    {
        public RichHTML()
            : base("no script tags please..!")
        {
        }

        public override bool IsValid(object value)
        {
            if (value.ToString().ToLower().Contains("<script>"))
            {
                return false;
            }
            return true;
        }

        public void OnMetadataCreated(ModelMetadata metadata)
        {
            metadata.RequestValidationEnabled = false;
        }

    }

This is enough for us to solve our problem. Following is an explanation:


  • First I’ve declared a class “RichHTML” decorated with attribute specification

  • I’ve inherited ValidationAttribute (found in System.ComponentModel.DataAnnotations.ValidationAttribute) which is a base class for all validation attributes.

  • I also implemented IMetadataAware interface. This provides an event handler OnMetadaCreated which is invoked quite early when model field is being constructed. Handler which throws HttpWebRequest exception, executes sometime after this.

  • I created a constructor which tells base that if an error comes, the message to display is “no script tags please..!”. You can instead set it by overriding ErrorMessage property

  • IsValid is overriden to check presence of “<script>” tag in content posted. If found IsValid is false otherwise true. If another tag too needs to be checked, only this method needs an update across application.

  • Finally and most importantly, I’ve set metadata.RequestValidationEnabled to false for this property. Setting this makes framework to bypass http request validation and prevents “Potentially dangerous Request.Form…” error.

You can now decorate your model with RichHTML instead of AllowHTML as following:
public class UserModel 
{
 [RichHTML]
 public string FirstName { get; set; }
}
show

Tuesday, March 20, 2012

Replacing OuterHTML with AJAXHelper.ActionLink


There are various wayswhich provides unobtrusive way of updating UI with response from server via AJAX. One such option provided by MVC framework is Ajax.ActionLink. For example,
@Ajax.ActionLink
(
      "TextOfLink", 
      "ActionName",
      "ControllerName", 
      new AjaxOptions() { UpdateTargetId = "DivToBeReplaced"}
)
Above code generates a link which when clicked, calls an action called “ActionName” of the controller “ControllerName” and what ever is returned from this action, is displayed in a div with id “DivToBeReplaced”. That’s so easy!But there is a minor caveat in using UpdateTargetID. By default, it replaces the contents of div and not the div itself. Which means in following Razor code,

<div id="mydiv">
    Some Text
    @Ajax.ActionLink(
          "Refresh",
          "Index", 
          new AjaxOptions(){UpdateTargetId = "myDiv"}
<div>

Clicking on generated action link would result in following:
<div id="mydiv">
<div id="mydiv">
    Some Text
    @Ajax.ActionLink
(
       "Refresh",
       "Index", 
       new AjaxOptions(){UpdateTargetId "myDiv"}
)
</div>
</div>
This is so because action link will replace what ever comes from server with the content inside mydiv and not mydiv itself (in other words, it replaces innerHTML and not OuterHTML)

Fix: Instead of using UpdateTargetId, use OnComplete event handler which takes as input a JavaScript method name (automatically called when view response is received from server)
@Ajax.ActionLink("TextOfLink",
"ActionName",
"ControllerName",
new AjaxOptions() { OnComplete= "setMyDiv"})
and in script:
function setMyDiv(data)
{
  $('#mydiv').replaceWith(data.responseText);
}
data is the object that contains response while responseText property returns response as a string. While divId is passed from view which needs to be replaced with response content. This gives a finer control over manipulating response and playing with DOM.

Q) What if div id is dynamically generated and hence not known in advance?
A) This is what I was stuck upon and found a cute hack. Internally, JQuery contains response in a variable called “xhr”. So, I was able to solve this problem as following:
@Ajax.ActionLink(
   "TextOfLink",
   "ActionName",
   "ControllerName",
   new  AjaxOptions() { OnComplete= "setSomeDiv(xhr,'" + Model.UniqueID +"')" })

where Model.UniqeId is some property of model containing unique Id. And the script:
function setSomeDiv(data, divId)
{
  $(document).find('#' + divId).replaceWith(data.responseText);
}

This works great!! Hope it helps someone!!

Do let me know if you've a better approach.

Friday, December 2, 2011

Understanding MVC Razor layouts


Q) What are ASP.NET MVC3 Razor Layouts?
You want a disclaimer, header and a menu on left to appear on all pages to bring in consistency to your web application. If you're from webforms background, you'd be quick enough to think of using a Master Page.
template
Similar to Masterpage, MVC 3 introduces concepts of layout. Similar to selecting master page in ASPX pages in page directive, in MVC you can specify layout at global or specific view level.

Q) When and how are they created?
When you add a new MVC3 application (either blank or internet or intranet), Visual Studio automatically adds a default layout file called “_layout.cshtml” , placed in shared folder of view.
location
Note: There is no special extension for layout file.
This layout is  automatically wired in another auto generated file called “_viewStart.cshtml” which contains following code:
@{
    Layout = "~/Views/Shared/CustomLayout.cshtml";
}

Of course, you can replace CustomLayout.cshtml with your custom html or alternatively replace layout file path with a different layout file. There is no naming convention. You can set “Layout”  to any .cshtml file.

Q) Can I have only one layout file?
You have 1 global layout file as mentioned in aforesaid section (_Layout.cshtml) which is generated by default as a boilerplate code. However, you can either replace it with your layout file or change its content. Also, if you have a requirement to use different layouts for a specific view, you can do so while adding a view (or later by editing Layout property in .chtml file)

customlayout


If you leave this box empty, automatically the layout as specified in _viewstart.cshtml is applied, otherwise the layout explicitly specified is applied. In above figure, for this view, _customlayout.cshtml will be applied.

Q) How do I inject views in master layout?

When a view is called, following process happens:

process

You can derive options from aforesaid diagram:


  • If you don't want to use any layout, set Layout = “”

@{
    ViewBag.Title = "Index";
    Layout = "";
}


  • To use a custom layout for a view, set  Layout to specific layout’s path

render

Q) How can I  inject view’s content in specific sections of layout?

Through – Sections!

sections



Besides, @RenderLayout, you can also define placeholders in layout file with specific name. For example, we created 2 placeholders @Header and @Disclaimer. In Views, create sections (with same name as in layout) and define content within curly braces {}.

All content with in section is rendered in respective placeholders, while everything else remaining is displayed by replacing @RenderBody

Q) What if my view has a section but layout doesn’t renders it or vice-versa?

If view has no layout specified, then there are no issues. But if a layout is specified, then either of the following scenarios would result in an error:
1) If Layout has a RenderSection(“somesection”) and there is no equivalent @section in view, then error comes.
2) If view contains any @section, which is not rendered in Layout, then also error comes.

To resolve 1), use IsSectionDefined(“viewname”) which checks if view has any section with specified name and accrodingly returns true false. So, where there is a probability of section not defined in a view, wrap the @RenderSection with this method.
@if (IsSectionDefined("somesection"))
    {
        @RenderSection("somesection")
    }

To resolve 2) you can either render section programmatically using Html.RenderPartial (explained in following sections).

Q) How can I extract sections in to separate view (for reusability)?

Through – Partial Views!

You can create partial views by checking “Create as partial view” checkbox, that appears in Add a new View popup. 

 partial

Partial views have nothing special. They are same as other views, its just they don’t have default code block on top.



Q) How can I render partial views into layouts?

using RenderPartial method.

@{
Html.RenderPartial(“myView”)
}

Note: MyView will be searched in context of current view directory and shared directory. If you view lies somewhere else, you must specify full path like “~/Home/Views/SomeFolder/MyView.cshtml

You can also use @Html.Partial(“viewName”)