Category: C#

How to avoid js files cache script bundle with razor

It happened to me, that I was working on an ASP.NET MVC Razor with AngularJs application, and every time that the team make a change in the AngularJs files and deploy to Production, the users start complaining about unresolved issues in the application. Those issues were because of the browser cache the JavaScript files in the client side. So in this article, I'll try to find an optimal solution to this problem, meaning that the javascript bundle should avoid cache when a new version of the application is deployed to production.
bundle cache

Avoiding browser cache:

We have to consider that one of the most popular techniques to avoid browsers cache with javascript files is to add a variable at the end of the file name, like this: src="/app/app.js?nocache=12365434576".

  <script type="text/javascript" src="/app/app.js?nocache=12365434576"></script>

Now this resolve the issue partially since 12365434576 it's going to be a random number that always going to avoid the cache, and we don't want that, we want to avoid cache only when a new version is deployed, for a better performance. So what we need to do is, instead of set the nocache var to a random number we are going to user the version of the application, like this:


Bundle Code:

We had a code like this to compose the bundle in App_Start/BoundleConfig.cs

 private static void AddAppBundles(BundleCollection bundles)
        {
            var path = "admin";
            var scriptBundle = new ScriptBundle("~/js/app");
            var FullPath = HttpContext.Current.Server.MapPath(string.Format("~/{0}", path));
            if (Directory.Exists(FullPath))
            {
                scriptBundle.Include(
                    // Order matters
                    string.Format("~/{0}/app.module.js", path),
                    string.Format("~/{0}/app.core.module.js", path)
                    )

                    .IncludeDirectory(string.Format("~/{0}", path), "*.module.js", true)
                    .IncludeDirectory(string.Format("~/{0}", path), "*.js", true);
            }
            bundles.Add(scriptBundle);
        }

With the code above we can include all the javascript files found in "path" variable in our _Layout.cshtml page, with this code:

@Scripts.Render("~/js/app")

The code is going to render something like this:

  <script type="text/javascript" src="/app/app.js"></script>
<script type="text/javascript" src="/app/config.js"></script>
<script type="text/javascript" src="/app/dashboard/dashboard.module.js"></script>
<script type="text/javascript" src="/app/layout/layout.module.js"></script>
<script type="text/javascript" src="/app/blocks/apiendpoint.config.js"></script>
<script type="text/javascript" src="/app/blocks/apiendpoint.provider.js"></script>

The question here is how we can render something like this src="/app/app.js?nocache=1.28.16145.10", when we render the bundle in razor.
We are going to use @Scripts.RenderFormat.

Solution:

@{  
    string version = typeof(yourProjectNamespace.WebApiApplication).Assembly.GetName().Version.ToString();
}
    <!--app scripts.-->
    @Scripts.RenderFormat("<script type=\"text/javascript\" src=\"{0}?nocache="+ version +"\"></script>", "~/js/app")

This is an example of the result rendered:

  <script type="text/javascript" src="/app/app.js?nocache=1.28.16145.10"></script>
<script type="text/javascript" src="/app/config.js?nocache=1.28.16145.10"></script>
<script type="text/javascript" src="/app/dashboard/dashboard.module.js?nocache=1.28.16145.10"></script>
<script type="text/javascript" src="/app/layout/layout.module.js?nocache=1.28.16145.10"></script>
<script type="text/javascript" src="/app/blocks/apiendpoint.config.js?nocache=1.28.16145.10"></script>
<script type="text/javascript" src="/app/blocks/apiendpoint.provider.js?nocache=1.28.16145.10"></script>

Hope this was helpful. 🙂

State Management in ASP.Net

In this article I'll try to cover the different techniques session state management in ASP.Net applications. With this we are going to be able to determine the best approach for our solution when we manage the session states in ASP.Net applications.
session state management

These are the session state management options in Asp.net

  • Off
  • StateServer
  • InProc
  • SQLServer
  • Cookies
  • Query String
  • Custom

Fot Off|StateServer|InProc|SQLServer, we will need to specify the session state tag in the web.config. This is a template code:

<sessionState mode="Off|StateServer|InProc|SQLServer"
              cookieless="true|false"
              timeout="number of minutes"
              stateConnectionString="tcpip=server:port"
              sqlConnectionString="sql connection string"
              stateNetworkTimeout="number of seconds"/>

Off Mode

Off mode, which disables session state.


StateServer Session State mode

StateServer Session State mode, which stores session state in a separate process called the ASP.NET state service. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm. StateServer session runs as a Windows service and would help to minimize database traffic.
Example:

<configuration>
  <system.web>
    <sessionState mode="StateServer"
      stateConnectionString="tcpip=SampleStateServer:42424"
      cookieless="false"
      timeout="20"/>
  </system.web>
</configuration>

InProc Session State

InProc Session State, this mode stores session state with the ASP.NET worker process (in memory on the Web server). It is not valid in a web farm configuration.
Example

<configuration>
   <system.web>
      <sessionState mode="InProc"
                    cookieless="true"
                    timeout="20"/>
      </sessionState>
   </system.web>
</configuration>

SqlServer Session State

SqlServer Session State. stores session state in a SQL Server database. This ensures that session state is preserved if the Web application is restarted and also makes session state available to multiple Web servers in a Web farm. Although, It does support a web farm configuration, you should not use this if you want to minimize database traffic.
Example:

<configuration>
  <system.web>
    <sessionState mode="SQLServer"
      sqlConnectionString="Integrated Security=SSPI;data 
        source=SampleSqlServer;" />
  </system.web>
</configuration>

Cookie State mode

Cookie State mode. Cookies are stored on the client, so the application would not be able to keep the state if they switched to a different device or a different browser. Also the user needs to have the cookies enabled in their browser


Query String

Query String It can be used for passing limited state information across request boundaries, this solution would not be able to keep the state if they switched to a different device. This solution will work even if the user have disabled the cookies in the browser.


Custom mode

Custom mode, which enables you to specify a custom storage provider.
Example:

<configuration>
  <connectionStrings>
    <add name="OdbcSessionServices" 
      connectionString="DSN=SessionState;" />
  </connectionStrings>

  <system.web>
    <sessionState 
      mode="Custom"
      customProvider="OdbcSessionProvider">
      <providers>
        <add name="OdbcSessionProvider"
          type="Samples.AspNet.Session.OdbcSessionStateStore"
          connectionStringName="OdbcSessionServices" 
          writeExceptionsToEventLog="false" />
      </providers>
    </sessionState>
  </system.web>
</configuration>

These are the options we have in Asp.net to manage the session state in an application. Hope this was helpful.

ASP.NET MVC Routers common questions

I'm doing this article as a self remainder of how to declare routers in ASP.NET MVC I will try to answer the most common questions about ASP.NET MVC Routers that I was able to find on internet. Hopefully this might help you as well. Routers

When you create a MVC application with Visual Studio, and you go to the RouteConfig.cs file this is the default code generate by the template:

 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", 
                                action = "Index", 
                                id = UrlParameter.Optional },
                constraints: new {id = @"\d+"}
            );

Most common questions about routers:

"Why do we use route.IgnoreRoute?"
This will tells the routing engine to ignore any requests that match the provided pattern "{resource}.axd/{*pathInfo}". In this case to ignore any requests to axd resources.

"Why the parameters in {} ?"
The {} indicates that the delimited string is a variable, it can anything. In the ignore route this is used so that any .axd requests are matched.

Why map MapRoute has First parameter "Default"
The first parameter is the route name. This can be used when referring to routes by name. It can be null
E.g.

routes.MapRoute(
  "Default", //Default Route
  "{controller}/{action}/{id}", // URL with parameters
   new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
);

routes.MapRoute(
  "Feedback", // Custom Route name
  "Feedback",
   new { controller = "Home", action = "Feedback" }
);

//Then you can call it like this:
@Html.RouteLink("Feedback");

What is the Second Parameter-"{controller}/{action}/{id}" for?
This is the pattern that is matched. In this case it is setting up the default route which is a url formed by the controller name, action name and an optional id. The url http://yoursite.com/Foo/Bar would call the Bar method on the Foo controller. Changing the url to http://mysite.com/Foo/Bar/1 would pass a parameter with the identifier id and value 1.

What is the third parameter?
The third parameter supplies defaults. In the case of the default route the default controller name is Home and the default action is Index. The outcome of this is that a request to http://yoursite.com would call the Index method on the Home controller. The id part of the route is specified as being optional with UrlParameter.Optional.

What is the fourth parameter?
The fourth parameter is for constraints, you can use regular expressions, in this example in particular this expression "\d+" match strings that are sequences of one or more digits (0-9).

How to create a custom Routers Constraint?
For this example we are going to create a Guid constraing, we have to create a class that inherit from IRouteConstraint and implement it:
routers implement interface
This is the code:

public class GuidConstraint : IRouteConstraint {

public bool Match(HttpContextBase httpContext, Route route, string parameterName, 
                  RouteValueDictionary values, RouteDirection routeDirection)
{
    if (values.ContainsKey(parameterName))
    {
        string stringValue = values[parameterName] as string;
        if (!string.IsNullOrEmpty(stringValue))
        {
            Guid guidValue;
            return Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty);
        }
    }
    return false;
}}

You can use it in the route like this:

routes.MapRoute("doubleGuid", "{controller}/{action}/{guid1}", 
                 new { controller = "YourController", action = "YourAction" }, 
                 new { guid1 = new GuidConstraint() });

Why we use new?
The new keyword is creating/instanciating an object using the object initializer syntax that was introduced in version 3 of the .Net framework.

Difference between “MapHttpRoute” and “MapRoute”?
ultimately both operate on the same underlying ASP.NET route table, the difference is that MapRoute is used for when the application is hosted in ASP.NET. MapHttpRoute is used for Web Apis for when hosting outside of ASP.NET, Web API wouldn't have to rely on System.Web.
Web API is not sitting on top of MVC, Web Forms, or, for that matter ASP.NET at all. It can be hosted within web context (ASP.NET) but can also be self hosted in a Console app, WPF, etc.

The major advantage of using routing is that it creates a convention for your Urls. If you created a new controller called Account and action methods called Index and Review then the methods would be available at /Account and Account/Review respectively.

Other resources:
http://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/creating-a-route-constraint-cs
https://msdn.microsoft.com/en-us/library/cc668201.aspx?f=255&MSPPError=-2147217396

How to create a custom controller factory ASP.Net MVC

I was reading about "Control application behavior by using MVC extensibility points" which is one of the objectives for the 70-486 Microsoft certification, and it was not clear to me, the explanation provided. So I decided to write about it to make clear for me, and I hope this help you as well.

An ASP.NET MVC application contains the following class:

public class HomeController: Controller
{
   public HomeController(Ilogger logger)//notice the parameter in the constructor
   {

   }
}

This throw an error with the DefaultControllerFactory see image below.
Dependency injection controller error

The application won't be able to load the HomeController because it have a parameter. You need to ensure that HomeController can be instantiated by the MVC framework. In order to accomplish this we are going to use dependency injection.

The solution is to create a custom controller factory.

It calls the default constructor of that class. To have the MVC framework create controller class instances for constructors that have parameters, you must use a custom controller factory. To accomplish this, you create a class that implements IControllerFactory and implement its methods. You then call the SetControllerFactory method of the ControllerBuilder class to an instance of your custom controller factory class.

Create the CustomControllerFactory that inherit from IControllerFactory:

 public class CustomControllerFactory : IControllerFactory
    {

        public CustomControllerFactory()
        {
        }


        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
             ILogger logger = new DefaultLogger();
        var myController = new HomeController(logger);
        return controller;
        }

        public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
             return SessionStateBehavior.Default;
        }

        public void ReleaseController(IController controller)
        {
            var disposable = myController as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }

        }
    }

 

book

Book Tip

MCSD Certification Toolkit (Exam 70-483): Programming in C
The MCSD 70-483 exam is the entry-level Microsoft certification exam for C# developers and this must-have resource offers essential coverage of the exam that will test your competency in C# programming.


Amazon

 

You can implement the CreateController() method with a more generic way, using reflection.

public class CustomControllerFactory : IControllerFactory
{
    private readonly string _controllerNamespace;
    public CustomControllerFactory(string controllerNamespace)
    {
        _controllerNamespace = controllerNamespace;
    }
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        ILogger logger = new DefaultLogger();
        Type controllerType = Type.GetType(string.Concat(_controllerNamespace, ".", controllerName, "Controller"));
        IController controller = Activator.CreateInstance(controllerType, new[] { logger }) as Controller;
        return controller;
    }
} 

Set your factory in Application_Start by using SetControllerFactory method:

 protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            ControllerBuilder.Current.SetControllerFactory(typeof(CustomControllerFactory));
        }

This could be one of the objective of the Microsoft certification exam 70-486, more specific for "Develop the user experience", sub-objective "Control application behavior by using MVC extensibility points".
Hope this helped you to understand how to do dependency injection in controllers with MVC.

External references:
http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection

IQueryable VS IEnumerable in C#

As C# developers we use IEnumerable and IQueryable for data manipulation almost all the time in our application projects, and for me, sometimes is confusing when to use one or another. So I searched in internet and created the table bellow so if I forget I can quickly come to this post and review the differences so I can get the most of each and make sure I use it correctly.

IQueryable IEnumerable

IEnumerable IQueryable
Namespace. System.Collections System.Linq
Derives from. No base interface. Derives from IEnumerable.
Deferred Execution. Supported. Supported.
Lazy Loading. Not Supported. Suported.
Suitable for. LINQ to Object and LINQ to XML queries. LINQ to SQL queries.
Custom Query. Doesn’t supports. Supports using CreateQuery and Execute methods.
Other characteristics. It is a read only collection.
It iterates only in forward direction.
It works with collection in local memory.
It does not support adding, removing objects on collection.
It provides enumerator to iterate collection in forward direction.
It implements IEnumerable,so the results can be iterated using foreach.
It is best suited to query external data sources,(like remote database, service) collections.
It works with queryable data provider.
It creates query using an Expression Tree.
It is used to query a queryable data source.
When to use... Working with the read only collection.
Need to read the objects in forward direction only.
Not concerned about thread safety.
Want to iterate the collection’s objects using foreach.
Working with the queryable datasource.
Need to apply filter on data at the datasource.
Need to apply paging , composition.
Working with external data source.
Needs to load data in deferred way.
Need to use foreach to iterate collection.

IEnumerable Example:

DataContext ctx = new DataContext ();
IEnumerable<People> collection = ctx.People.Where(p => p.Name.StartsWith("j"));
collection = collection.Take<People>(20); 

Generated SQL statements of above query will be :

 SELECT [t0].[ID], [t0].[Name], [t0].[Salary] FROM [People] AS [t0]
WHERE [t0].[Name] LIKE @p0

Notice that in this query "top 20" is missing since IEnumerable place all the records in memory and filters on client side.

IQeryable Example:

 DataContext ctx = new DataContext ();
IQueryable<People> collection = ctx.People.Where(p => p.Name.StartsWith("j"));
collection = collection.Take<People>(20); 

Generated SQL statements of above query will be :

 
SELECT TOP 20 [t0].[ID], [t0].[Name], [t0].[Salary] FROM [People] AS [t0]
WHERE [t0].[Name] LIKE @p0

Notice that in this query "top 20" is exist, since IQueryable executes query in SQL server with all filters, and put in memory the result already filtered.

Official documentation for IQueryable and IEnumerable:

https://msdn.microsoft.com/en-us/library/system.linq.iqueryable(v=vs.100).aspx
https://msdn.microsoft.com/en-us/library/system.collections.ienumerable(v=vs.110).aspx

OrderBy argument as String using Linq C#

How to specify the OrderBy method using LINQ, with a string value as a parameter.

How do I specify the argument passed to OrderBy method with LINQ, using a string value as a parameter?
This is the current implementation:

var list =   _dbContext.Advertisement
.Where(y => (DateTime.Now > y.StartDate) && (DateTime.Now < y.EndDate) && 
!y.Archived && adId.Contains(y.StoreId)) .OrderBy(x => x.Name).ToList();

Instead of x.Name, I want to take x.Name as a string parameter and make it more dynamic. For example:

string orderByParam = "Name";
var list =   _dbContext.Advertisement
.Where(y => (DateTime.Now > y.StartDate) && (DateTime.Now < y.EndDate) && 
!y.Archived && adId.Contains(y.StoreId))
.OrderBy(orderByParam).ToList();

Obviously LINQ’s OrderBy() method doesn’t accept string parameters, only lambda expressions.

Possible solution:

Using reflection…

var orderBy = String.IsNullOrEmpty(orderBy) ? "Name" : orderBy;
var dynamicPropFromStr = typeof(Advertisement).GetProperty(orderBy); 

var list =   _dbContext.Advertisement
.Where(y => (DateTime.Now > y.StartDate) && (DateTime.Now < y.EndDate) && 
!y.Archived && adId.Contains(y.StoreId)) 
.OrderBy(x => dynamicPropFromStr.GetValue(x, null)).ToList();

This will certainly solve the problem, but this code will throw an exception:

An exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll but was not handled in user code.

Additional information: LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object, System.Object[])' method, and this method cannot be translated into a store expression.

OrderBy Exception

This happen because LINQ to Entities uses IQueryable type, and within Where, OrderBy etc only support Lambda Expressions cannot contain any C# specific code, they can only contain expression tree, which is translated to SQL. You cannot call any arbitrary methods there, except the ones that are mentioned by EF documentation such as SqlFunctions etc.

To avoid this exception you can convert the expression to Enumerable with AsEnumerable() method, before the OrderBy:


var list = _dbContext.Advertisement
.Where(y => (DateTime.Now > y.StartDate) && (DateTime.Now < y.EndDate) && 
!y.Archived && adId.Contains(y.StoreId)).AsEnumerable() 
.OrderBy(x => dynamicPropFromStr.GetValue(x, null)).ToList();

References:

https://msdn.microsoft.com/en-us/library/vstudio/bb534966(v=vs.100).aspx
If you have a solution for this, don't be shy and share it with us. 🙂