Getting Entity Framework to recognise the return type of a Stored Procedure that returns a #temp table

The Situation

I recently wanted to declare a table, insert data into it and then, depending on a variable passed in to the stored procedure (@i_bitCurrent), either return the contents of the table, or filter the contents with a Where clause and return them (3 options in total). The reason I wanted to use the temporary table approach was to avoid duplicating the long select statement 3 times, with just the Where part of the statement being different (or have three separate stored procedures).

The Problem

I got the stored procedure to work, and return the expected data set when run from within Microsoft SQL Management Studio, but Entity Framework (in Visual Studio 2012) refused to recognise the return type (it saw a return type of nullable int).

The Solution

After Googling the problem I found a similar problem and suggested answer on Stack Overflow – I needed to supply a faux data contract that Entity Framework would then use as the return type. The faux data contract is the first IF statement in the code below.

The Code

This is a cut-down version of the code, so you can see why I did not want to duplicate it (making changes would ahve been a nightmare…) The faux data contract IF statement at the beginning will never be executed as 1 will never equal 2. It is simply there to get Entity Framework to recognise the return type. It will need to be updated if the temporary table is ever updated.

IF 1 = 2
  BEGIN
    SELECT
    cast(null as int) as UserId
    ,cast(null as nvarchar(250)) as Username
    ,cast(null as int) as RoleCount
    ,cast(null as datetime) as UserRevoked
    ,cast(null as bit) as Locked
    ,cast(null as bit) as ForcePassChange
    ,cast(null as varchar(200)) as ClientName
    WHERE
    1 = 2 
  END

CREATE table #tmpResults (
   UserId int, 
   Username nvarchar(250), 
   RoleCount int, 
   UserRevoked datetime, 
   Locked bit, 
   ForcePassChange bit, 
   ClientName varchar(200)
)

INSERT #tmpResults (
   UserId,
   Username,
   RoleCount,
   UserRevoked,
   Locked,
   ForcePassChange,
   ClientName
)
SELECT
   u.UserId,
   u.Username,
   (SELECT COUNT(*) 
      FROM USERROLE 
      WHERE FKUserId = u.UserId AND Revoked IS NULL),
   u.Revoked,
   u.Locked,
   u.ForcePassChange,
   c.Name
FROM [USER] u LEFT OUTER JOIN [CLIENTS].[dbo].[CLIENT] c on u.FkClientId = c.ID
ORDER BY u.UserId

IF(@i_bitCurrent IS NULL)
  BEGIN
     SELECT * FROM #tmpResults
  END
IF(@i_bitCurrent = 1)
  BEGIN
     SELECT * FROM #tmpResults
     WHERE (UserRevoked IS NULL OR UserRevoked > GetDate())
     ORDER BY UserId
  END
IF(@i_bitCurrent = 0)
  BEGIN
     SELECT * FROM #tmpResults
     WHERE (UserRevoked IS NOT NULL AND UserRevoked < GetDate())
     ORDER BY UserId
  END

Entity Framework / Visual Studio

Then when I removed the stored procedure from the model in Visual Studio (from both the Stored Procedures / Functions folder and Function Imports folder), and refreshed the model from the database, the stored procedure was added correctly and a Complex Type created with the correct return value.

That is an Entity Framework Hack!

Note

Ints and bits (bools) will be returned as nullable, so you may need to use returnType.fieldName.Value ( in C#, or the equivalent in the language you are using) to access the value of these types in the returned type.

Tagged , , , , , , , , , , ,

Progromatically get SessionId Cookie name used in an asp.net application

The default name for the SessionId cookie in an Asp.Net application is ASP.NET_SessionId, but this can be changed in the web.config, e.g.

<sessionState cookieName="FooBar" />

I wanted to get the name of the SessionId cookie for the web app that was implementing my class library. I knew the dll would be implemented by many other future projects, written by many other developers, so I could not rely on any standard naming convention. I needed to know what the SessionId cookie was called in any situation.

Progromatically getting the SessionId cookie name would also be good to use in all situations as you never know when another developer working on the same project may decide to change something like the SessionId cookie name; this could easily result in broken code. That developer might even be you!

So here is the method I wrote to return the SessionId cookie name, along with the extra references you will need for this method:

using System.Configuration;
using System.Web.Configuration;
internal string GetSessionIdCookieName()
{
    SessionStateSection sessionStateSection = (SessionStateSection)ConfigurationManager
                                              .GetSection("system.web/sessionState");
    return sessionStateSection != null ? sessionStateSection.CookieName : null;
}

I can now use this to get the cookie name, and if it is null I can create and save my own SessionId cookie.

Thank you to Claudio Redi on StackExchange for his code which I adapted.

Tagged , , , , , , , , ,

Get the executing assembly of a web app referencing a class library

The Problem

I needed to check that any web app that was referencing my class library was giving me a valid controller and action name in some settings in its web.config, so that when I used them in a redirection there would be no errors because they did not exist.

When I used

Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();

to get the types I only got the types from the class library. I tried

Type[] types = System.Reflection.Assembly.GetEntryAssembly().GetTypes();

but got null for GetEntryAssembly(). It seems this does not work for web apps.

This was another approach that did not work:

Assembly a = new StackTrace().GetFrames().Last().GetMethod().Module.Assembly;

The Solution

I finally solved it with the help of StackExchange

To get the assembly:

private static Assembly GetWebEntryAssembly()
{
   if (System.Web.HttpContext.Current == null || System.Web.HttpContext.Current.ApplicationInstance == null)
   {
       return null;
   }
   var type = System.Web.HttpContext.Current.ApplicationInstance.GetType();
   while (type != null && type.Namespace == "ASP")
   {
       type = type.BaseType;
   }
   return type == null ? null : type.Assembly;
}

Check if a controller with an action exists, using GetWebEntryAssembly()

private static bool CheckValid(string controller, string action)
{
    if (!controller.Contains("Controller"))
    {
        controller = controller + "Controller";
    }
    // Get assembly
    Assembly a = GetWebEntryAssembly();
    if (a != null)
    {
        // Get types
        Type[] types = a.GetTypes();
        // Get controller with this name, if it exists
        Type type = types.Where( t => t.Name == controller ).SingleOrDefault();
        // Check if controller contains action, if specified
        if (string.IsNullOrEmpty(action))
        {
            // no action specified
            return type != null ? true : false;
        }
        return (type != null && type.GetMethod(action) != null) ? true : false;
    }
    return false;
}

Notes

  • This method checks that the controller name passed through is the full name, e.g. ‘HomeController’ as this is required.
  • The method does not require an action name to be passed in so that a controller’s existence can be verified without verifying an action name within it. This is useful as the controller and action are specified as separate app settings in the web.config, so I can verify the controller and then verify the action separately, also feeding in the controller.
Tagged , , , , , , , , ,

Using Custom Action Filters in Class Libraries

I have recently been creating a class library that many MVC web applications are going to reference, and I wanted those applications to be able to implement some custom Action Filters so they did not need to duplicate code. I had originally thought this was not possible, due to the different applications needing redirection to their respective controllers and actions, but once I discovered how easy it was to pass in variables to an Action Filter, or to access predefined attributes in the individual web applications’ respective web.config files I realised it would not be too difficult to implement these Action Filters.

Please see my previous post if you want more information on Passing Variables to Custom Action Filters.

Must Have Role Example

One of the action filters I wished to implement was an authorisation attribute, which could be used to mark individual controllers or individual actions as only accessible to users with certain roles. Here I will show an example of the attribute restricting access to a whole controller. MyClassLibrary is referenced by MyWebProject.

MyWebProject Controller

using System.Web.Mvc;
using MyClassLibrary.Filters;

namespace MyWebProject.Controllers
{
    [MustHaveRole(Role="admin")]
    public class AdminController : BaseController
    {
        public ActionResult Index()
        {
            return View();
        }
    }
}

MyClassLibrary Action Filter

using System.Web.Mvc;
using System.Web.Routing;
using System.Configuration;

namespace MyClassLibrary.Filters
{
    public class MustHaveRoleAttribute : ActionFilterAttribute
    {
        public string Role {get; set;}

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Get currently logged in user
            // Check if user has a role using string Role
            // Redirect if user does not have the specified role
            if(!hasRole)
            {
                string c = ConfigurationManager.AppSettings["UnauthController"].ToString();
                string a = ConfigurationManager.AppSettings["UnauthAction"].ToString();
                filterContext.Result = new RedirectToRouteResult(
		    new RouteValueDictionary
		    {
			{ "controller", string.IsNullOrEmpty(c) ? "Home" : c }, 
			{ "action", string.IsNullOrEmpty(a) ? "Index" : a }
		    }
		);
            }
        {
    }
}

If the user does not have the specified role (is not authorised) they are redirected to an ‘unauthorised’ controller and action. These are specified in the web application’s web.config file or are set to defaults of Home and Index if there is a problem with retrieving those values. The specified action may just be a view which tells the user they are not authorised to access that area, but it is up to the developer of each web app to decide that.

Tagged , , , , , , ,

Passing in variables to custom Action Filters

Sometimes it is useful to have a reusable custom action filter, for example for checking user authorisation to access part of the application. I would prefer not to have a separate filter for each type of user, e.g. MustBeAdminAttribute, MustBeManagerAttribute, etc. There are several ways to pass variables to a custom action filter and I will start with what I think is the best method for this particular expample.

Variables defined in the filter

The variable is defined in the filter and assigned in the controller. This can be done for multiple variables.

Controller code

[MustHaveRole(Role="admin")]
public ActionResult AdminSection()
{
    return View();
}

Action Filter

public class MustHaveRoleAttribute : ActionFilterAttribute
{
    public string Role { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!string.IsNullOrEmpty(Role))
        {
            // Use Role string to check if the current user has that role
        }
    }		
}

Access a variable defined in the Action (ActionExecutingContext)

Variables defined in the action can be accessed via the ActionExecutingContext

Controller code

[MustHaveRole]
public ActionResult AdminSection()
{
    string role = "admin";
    return View();
}

Action Filter

public class MustHaveRoleAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string role = filterContext.ActionParameters.SingleOrDefault(p => p.Key == "role").Value.ToString();
        if (!string.IsNullOrEmpty(role)) 
        { 
            // Use role string to check if the current user has that role 
        }
    }
}

Access a variable passed to the Action (ActionExecutingContext)

This is done in the same way as accessing a variable defined in the action.

Controller code

[MustHaveRole]
public ActionResult AdminSection(string role)
{
    return View();
}

Action Filter

public class MustHaveRoleAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string role = filterContext.ActionParameters.SingleOrDefault(p => p.Key == "role").Value.ToString();
        if (!string.IsNullOrEmpty(role)) 
        { 
            // Use role string to check if the current user has that role 
        }
    }
}

Access Controller Properties and Variables (ActionExecutingContext)

You can also access controller properties and values using the ActionExecutingContext

Controller code

[MustHaveRole]
public ActionResult AdminSection()
{
    ViewBag.Role = "admin";
    return View();
}

Action Filter

public class MustHaveRoleAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string role = filterContext.Controller.ViewBag["Role"].ToString();
        if (!string.IsNullOrEmpty(role)) 
        { 
            // Use role string to check if the current user has that role 
        }
        // Further examples
        string actionName = (string)filterContext.RouteData.Values["action"];
        string controllerName = (string)filterContext.RouteData.Values["controller"];
    }
}
Tagged , , , , , , , ,

Storing a byte array in a Cookie (nom!) C# MVC

It seems that cookies can eat store just about any kind of data, but keeping to a limit of 20 cookies per domain and 4096 bytes per cookie is the safe way to do it (source).

I needed to store a byte array in a cookie (encrypted data) and Brian Pedersen’s article on streaming objects into cookies helped me to come up with the solution.

The original C# code I came up with did not work

// Write cookie
HttpCookie cookie = new HttpCookie("myCookie");
cookie.Value = System.Text.Encoding.UTF8.GetString(myByteArray);
Response.Cookies.Add(cookie);
// Read cookie
HttpCookie c = Request.Cookies["myCookie"];
byte[] retrievedByteArray = System.Text.Encoding.UTF8.GetBytes(c.Value);

For some reason what I got back was not the same as what I put in (more bytes!).

However using Convert, like Brian, did work

// Write cookie
HttpCookie cookie = new HttpCookie("myCookie");
cookie.Value = Convert.ToBase64String(myByteArray);
Response.Cookies.Add(cookie);
// Read cookie
HttpCookie c = Request.Cookies["myCookie"];
byte[] retrievedByteArray = Convert.FromBase64String(c.Value);

Note

The above code will work in a Controller, to do the same thing elsewhere (e.g. within a class) use HttpContext.Current.Response.Cookies and HttpContext.Current.Request.Cookies.

For example:

HttpContext.Current.Response.Cookies.Add(cookie);

For more information on storing objects in cookies please see Brian Pedersen’s blog post.

Tagged , , , , , , , , , ,

Retrieving parameters from the query string in the URL in .Net

Here is a nice easy way to get the individual parameter values from the URL, returning either a NameValueCollection (System.Collections.Specialized.NameValueCollection HttpRequestBase.QueryString) of all parameters in the query string, or a string value of a particular named parameter.

Return a NameValueCollection of all parameters

In a controller

var parameters = HttpContext.Request.QueryString;

In a view

var parameters = HttpContext.Current.Request.QueryString;

In an attribute (filter)

public class MyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var parameters = filterContext.HttpContext.Request.QueryString;
        ...
    }
}

Return a string of an individually named parameter from the query string

In a controller

var value = HttpContext.Request.QueryString["valueName"];

In a view

var value = HttpContext.Current.Request.QueryString["valueName"];

In an attribute (filter)

public class MyAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var value = filterContext.HttpContext.Request.QueryString["valueName"];
        ...
    }
}

Note

When requesting a named parameter, if the named parameter does not exist it will return null (rather than causing an exception).

if (HttpContext.Request.QueryString["valueName"] == null)
{
    // valueName does not exist in the query string
}

Follow my blog with Bloglovin

Tagged , , , , , , , , ,

App Offline page that refreshes when the site is back online

I created an app_offline.htm page to place in my site’s folder while I was deploying a new version, but I didn’t want to put a ‘click this link to refresh’ or a suggestion to refresh the page. That seemed to be pushing my problem onto the user.

I decided that jQuery would probably be the way to go, and so added a reference to Google’s latest version of jQuery 1.x (we supposrt IE7 and jQuery 2.x is IE9+):

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

Research

I did some googling and found an article on GitHub by Dunston. He had created an app_offline.htm page for his deployment that used jQuery to check, every 10 seconds, if the site was back up.

My Code

For my purposes I had to make a few tweaks, but this is what I came up with:

<script type="text/javascript">
   $(document).ready(function () {
      $("#year").text((new Date).getFullYear());
      if (window.location.protocol != "https:") 
      { 
         window.location.href = "https:" + window.location.href.substring(window.location.protocol.length); 
      }
   });
   (function ($, win){
      $(function (){
         var checkSite = function (){
            $.get('/').success(function (){
               win.location.reload(true);
            }).error(function (){
            });
         }
         win.setInterval($.proxy(checkSite, this), 10000);
      });
   } (jQuery, window));
</script>

What it does

When the page loads it:

  • updates the year in a copyright statement to the current year
  • checks if the current location protocol is https (which my site runs under), and if not redirects to the same url but with the https protocol

Every 10 seconds it:

  • checks to see if the root of the site is available (if the app_offline.htm file is still there it will fail, otherwise it will be a success)
  • on success the window reloads, and the site will load (the original url that was used)
  • on error nothing happens until another 10 seconds has passed

Why the redirect to https?

My site runs completely under https and all users should be coming in using the https protocol, but if they don’t they are automatically redirected to https. This means that if the above script checks to see if the site is available under http (and the app_offline.htm file has been removed) it will receive a redirect to https, which it sees as a failure. It will therefore never try to refresh the window as it will always think the site is down.

I first tried forcing the url that was checked to be https, but this caused an error:

XMLHttpRequest cannot load https://www.mysite.com/ Origin http://www.mysite.com/ is not allowed by Access-Control-Allow-Origin.

So I couldn’t make an https request when the current page (app_offline.htm) had been requested by http. A good security feature I suppose.

This is why I had to check the protocol on page load and then redirect to https if necessary. The jQuery then automatically checks for the https version of the site as the app_offline.htm page was loaded with this protocol. The check is allowed by the server AND no redirect is returned (as with an http request) so when the app_offline.htm page is removed the page refreshes.

No further user interaction required; they can make a cup of tea.

Tagged , , , , , , , , , ,

Getting IE7 and below to use @media print{} css

The Problem

My print css is defined in my main css file in @media print{…}. IE7 and below don’t seem to understand this.

Putting the css into another css file and using the conditional tags to add it to the head means that IE can apply the css, but how do I know when the user wants to print? And how do I know when they want to view the page normally?

The Solution

When a user clicks on my print icon (in IE7 or below) a css link element is dynamically applied to the head element, JavaScript calls window.print(), then the css link element is removed from the head element.

It almost sounds simple. It took a long time to find a working solution to this.

The Issues

1. Is the browser <= IE7?

I discovered (on StackOverflow) that a way to do this, that apparently cannot be fooled, is to use conditional comments to add an element to the DOM, and test against it.

In my <head> element

<!--[if lte IE 7]> <meta name="ie" id="ie" class="fail"/> <![endif]-->

Note: lte means <= (Less Than or Equal)

In my jQuery

if ($('meta#ie').hasClass('fail'))
{
 // browser is <= IE7
}

2. IE7 doesn’t allow appending to the head element.

This does not work in IE7:

$('head').append('<link rel="stylesheet" src="print.css" type="text/css"');

Instead you have to use the following:

if (document.createStyleSheet) {
    document.createStyleSheet("print.css");
}

Note: This if statement is also a good test for any IE browser (other browsers don’t have document.createStyleSheet).

3. The page shouldn’t show with the print css after printing.

I needed to remove the print css after the print command was issued. At first I thought I may need to set a timeout for the removal, but in fact not having a timeout around the removal of the link meant that the user did not ever see the print css applied to the page. Magic!

In my jQuery

$('head link:last').remove();

4. IE does not understand display: table-cell

This was used in my print css on a table cell that was display: none in the screen css. Luckily replacing this with display: inline in the IE print css worked. In other browsers this broke the layout; they required display: table-cell.

In my print.css

td.printOnly {
    display:inline;
}

The Final Solution

Head Element

<!--[if lte IE 7]> <meta name="ie" id="ie" class="fail"/> <![endif]-->

jQuery

$('a.ico-print').click(function ()
{
   if ($('meta#ie').hasClass('fail'))
   {
      if (document.createStyleSheet) 
      {
         document.createStyleSheet("ie7print.css");
      }
   }
   if (window.print) 
   { 
      window.print(); 
   }
   if ($('meta#ie').hasClass('fail'))
   {
      $('head link:last').remove();
   }
});

Print.css

td.printOnly {
    display:inline;
}
Tagged , , , , , , ,

Config Transform Files for changing Web.config for release (ASP.Net 4.0)

You can change parts of the web.config between different builds (e.g. debug and release). I used it to change whether cookies must only be sent and received over ssl.
It is also useful for changing connection strings from debug to live versions and also user defined keys (examples below).

Clicking the arrow next to Web.config (in the Solution Explorer Visual Studio)  reveals the various transform files. If you have added more build types you can add more transform files by right clicking on Web.config and selecting Add Config Transform.

Examples

Double-click a transform file to open it and see what it is doing. It has some examples, but the syntax I required for the httpcookies element was a different to these.

Remove debug attribute

System.web already contained one transform, which removes the debug attribute from the compilation element within the system.web element.

Web.Release.Config

<system.web>
    <compilation xdt:Transform="RemoveAttributes(debug)" />
</system.web>

Debug

<system.web>
    <compilation debug="true" targetFramework="4.0">
        ...
    </compilation>
    ...
</system.web>

Release

<system.web>
    <compilation targetFramework="4.0">
        ...
    </compilation>
    ...
</system.web>

Require cookies to be transmitted and requested only over a secure connection

I added another transform which changes the value of a named attribute (requireSSL) in a named element (httpCookies) within the system.web element.

Web.Release.Config

<system.web>
    ...
    <httpCookies requireSSL="true" xdt:Transform="SetAttributes(requireSSL)" />
</system.web>

Debug

<system.web>
    <httpCookies requireSSL="false" />
    ...
</system.web>

Release

<system.web>
    <httpCookies requireSSL="true" />
    ...
</system.web>

Change the value of a defined key

I also added another transform which changes the value attribute of an add element by matching the key attribute (live) within the appSettings element.

Web.Release.Config

<appSettings>
    <add key="live" value="true" xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)" />
</appSettings>

Debug

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

Release

<appSettings>
    ...
    <add key="live" value="true" />
</appSettings>

Changing a connection string

I did not need this myself but the following changes the connectionString attribute of an add element (within the connectionStrings element) by matching the name attribute (MyDB) and changes the value of the connectionString attribute to ReleaseSQLServer. Note that the attribute name (connectionString) does not need to be specified. You can change multiple attributes this way, by specifying each attribute and its new value (e.g. including providerName=”value” in the add element below).

Web.Release.Config

<connectionStrings>
    <add name="MyDB" connectionString="ReleaseSQLServer" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>

Debug

<connectionStrings>
    <add name="MyDB" connectionString="DebugSQLServer" providerName="System.Data.EntityClient" />
</connectionStrings>

Release

<connectionStrings>
    <add name="MyDB" connectionString="ReleaseSQLServer" providerName="System.Data.EntityClient" />
</connectionStrings>

Conclusion

Config transform files seem a very useful tool when using Visual Studio to publish your projects, and not using your own build scripts.

More useful information

Dan Maharry’s explanation of config transform files
MSDN Article on config transform files

Tagged , , , , , , ,