Policy Based Authorization in Windows Identity Foundation (WIF) – Part I

I wrote before about Claims based authentication here and a sample IP-STS to perform Authentication, but Authentication is not just enough for any application, it also requires Authorization, this is required to protect your resources and actions. Traditionally, its been achieved via RBAC – Role based access control using IPrincipal‘s IsInRole method. It verifies if current logged in user belongs to a certain group or not and allow to access the resource based on role, for example an Administrator will have ‘Administrator’ Role assigned to him and once validated he will have access to Admin section of the site. This works in WIF as well but with more granular properties getting added to User in the form of Claims it is really impossible to categorize these properties in role and add users to that role. Also, with RBAC a large amount of decision logic get embedded in the code.

Policy Based Authorization is a good choice to make decision based on available User Claims. WIF provided ClaimsAuthorizationManager is a very open-ended flexible extension point to integrate authorization mechanism including policy based authorization.

ClaimsAuthorizationManager

WIF has a HttpModule ClaimsAuthorizationModule which handles HttpApplication’s AuthorizeRequest to validate the incoming request.

public class ClaimsAuthorizationModule : IHttpModule
{

 

public void Init(HttpApplication context)
{
    if (context == null)
    {
        throw DiagnosticUtil.ExceptionUtil.ThrowHelperArgumentNull("context");
    }
    this._authorizationManager = FederatedAuthentication.ServiceConfiguration.ClaimsAuthorizationManager;
    context.AuthorizeRequest += new EventHandler(this.OnAuthorizeRequest);
}

Internally, AuthorizeRequest handler calls Authorize method which intern invokes ClaimsAuthorizationManager’s CheckAccess with current ClaimsPrincipal, requested Uri and Http request method.

protected virtual void OnAuthorizeRequest(object sender, EventArgs args)
{
    if (!this.Authorize())
    {

 

protected virtual bool Authorize()
{
    bool flag = true;
    HttpRequest request = HttpContext.Current.Request;
    IClaimsPrincipal currentPrincipal = Thread.CurrentPrincipal as IClaimsPrincipal;
    // removed few lines from original code to keep it simple
    if (this.ClaimsAuthorizationManager != null)
    {
        flag = this.ClaimsAuthorizationManager.CheckAccess(new AuthorizationContext(currentPrincipal, request.Url.AbsoluteUri, request.HttpMethod));
    }
    return flag;
}

Like IPrincipal, ClaimsAuthorizationManager has a single method i.e. CheckAccess but it is more granular by considering the requested resource and action type. CheckAccess verifies if user is authorize to access the requested resource or not, the default implementation returns true.

I explained it through a sample earlier for RBAC here, this assumes that user is assigned to a ClaimType Role with Sales value.

WIF’s document does comes with a sample policy based implementation and it pretty much covers simple Uri based scenario where it verifies if user is authorized to see certain Uris based claims assigned to him.

Another sample implementation can be found here.

I guess this is more than enough from the introduction point of view, in the next part I will cover Policy based authorization with XACML and a sample implementation based on XACML.NET.

Advertisements
Posted in Security, WIF | Leave a comment

Developing an Active STS – A Fun Project

Lately, I have been playing around with WIF to build an Active STS. I didn’t have access to necessary tools to build this on .NET 4.5 and I used .NET 4.0 to start with, this difference is significant because WIF is now part of .NET 4.5 and deeply embedded with .NET libraries, though conversion from this 4.0 to 4.5 shouldn’t be too hard.

Few weeks back I wrote about WIF here, its basics and the difference between .NET 4.0 and 4.5.

This article discussed following

  1. Implement Active STS with WIF & .NET 4.0
  2. Consuming Active STS in a MVC Application

Alright, lets talk about what is Active STS and what we can do with it.

Active STS – MSDN say’s – “A security token service (STS) is the service component that builds, signs, and issues security tokens according to the WS-Trust and WS-Federation protocols.”

The definition is really true, STS based authentication decouple the authentication logic from application, now application is responsible for authorizing the user based on Claims provided by STS and focus on application logic.

Federation where user is authenticated by one STS but they can have access to resources in other application if there is a trust relationship between the STS consumed by other application.

STS is build on top of WS-Trust specification, it describes issuing, renewing and validating of security tokens and broker the trust relationship between the participant in a secure message communication. Based on WS-Trust specification, Message is sent in the form of “Request for Security Token” and response is return in the form of “Request for Security Token Response”. For RST & RSTR, please refer the details here.

Building an Active STS

An Active-STS is consist of following

  1. A custom class derived from SecurityTokenService
  2. A WCF Service to host the SecurityTokenService
  3. Few Helper classes
  4. A MVC Client which will use the STS for authentication

SecurityTokenService

For Active-STS, most of the functionality is centered around the inherited class SecurityTokenService, it has two abstract method which needs to implemented in order to implement the functionality.

  1. GetScope
  2. This method checks if the requester is recognized by the STS and set Signin credential for RSTR.

  3. GetOutputClaimsIdentity
  4. This method gets called from Claims issuance pipeline when a client (implementation of IWSTrustChannelContract) request the token through Issue method (See the code – LoginService in StsClient). This method takes an incoming claims principal and return a new ClaimsIdentity with added claims.

These two method can be extended to plug-in multiple relying party client.

WCF Host and Configure

In order to host this service with WCF, an extension of WSTrustServiceHostFactory is required, which will create the service host to service the request. This is normal practices as like any other WCF Service host except, you are inheriting from WSTrustServiceHostFactory than ServiceHostFactory.

Couple of standard configuration required in WCF Service web.config file to make it working

  1. microsoft.identityModel section configuration in configSections and section configuration
  2. serviceBehaviour and bindings configuration in serviceModel.
  3. service certificate configuration, for this sample I am using localhost default certificate both for client and server.

I ran into issues while using the user name and password to validate the requesting client and seems only workaround to pass that is to create a derived implementation of UserNameSecurityTokenHandler, also before adding this configuration default TokenHandler – WindowsUserNameSecurityTokenHandler needs to removed.

  <securityTokenHandlers>
        <remove type="Microsoft.IdentityModel.Tokens.WindowsUserNameSecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        <add type="CPrakash.Security.ActiveSTS.RealmSTS.CustomUserNameSecurityTokenHandler, CPrakash.Security.ActiveSTS.RealmSTS" />
      </securityTokenHandlers>

RP Client

In my example, I have taken MVC as a client application but it can be any application eg. WebForms. In the example application, I removed the Membership method calls and added a LoginService which has custom code to call the STS from code with the supplied credential.

SessionSecurityToken sessionToken;
if (new StsClient.Services.LoginService().ValidateUser(model.UserName, model.Password, out sessionToken))
{
  ... // code after validation

If you look at the LoginService code, ValidateUser method takes supplied user name and password and pass it as credential to WSTrustChannelFactory.

SessionSecurityToken sessionToken;
var factory = new WSTrustChannelFactory(
                new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
                new EndpointAddress("https://localhost/ActiveSTS/SecurityTokenService.svc"));

factory.Credentials.SupportInteractive = false;
factory.Credentials.UserName.UserName = userId;
factory.Credentials.UserName.Password = password;

It builds the RST (request for secured token) and calls the issue method to request the secured token from service.

 var rst = new RequestSecurityToken
 {
     RequestType = RequestTypes.Issue,
     AppliesTo = new EndpointAddress("https://localhost/stsclient/"),
     KeyType = KeyTypes.Bearer,
     TokenType = Microsoft.IdentityModel.Tokens.SecurityTokenTypes.Saml11TokenProfile
 };

 var channel = factory.CreateChannel();
 var genericToken = channel.Issue(rst) as System.IdentityModel.Tokens.GenericXmlSecurityToken;

Once we have the token retrieved from service, we can create the session token out of it and it will be used to validate the user in subsequent request.

// parse token
var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader(new StringReader(genericToken.TokenXml.OuterXml)));
var identity = handlers.ValidateToken(token).First();

// create session token
sessionToken = new SessionSecurityToken(ClaimsPrincipal.CreateFromIdentity(identity));

Last piece to write the session token to client machine using cookie through WIF’s SessionAuthenticationModule‘s WriteSessionTokenToCookie method.

FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
Thread.CurrentPrincipal = sessionToken.ClaimsPrincipal;

Source code for this project is available at GitHub

Posted in WIF | Tagged , , , | 2 Comments

Identity in .NET 4.5 (aka WIF)

This article is based on the presentation given by Brock Allen and I would like to thanks him that he allowed me to use his presentation and code.

Pleae refer his presentation here.

http://brockallen.com/2012/10/16/demos-microsoft-devboston-windows-identity-foundation-in-net-4-5/

Traditional Approach to Authentication –

Authentication is the intrinsic part of the application, any or every application need authentication at some point of time. As every application needs it, same authentication logic or processes gets implemented in every application, sometime change in the authentication mechanism needs application changes.

Also with increasing uses of different authentication service provider like Google, Facebook or any other provider there is a need to outsource authentication or trust a provider which does authentication on behalf of application.

Windows Identity Foundation solves this problem in many ways and provides flexibility to focus on application code rather than authentication/authorization.

Identity in Microsoft.NET –

Identity has been at the center for security in .NET Framework 1.0, in simple terms Identity represents the user on whose behalf the code is running or what a user can do (Role), this include resource access, i/o operations or any other operation within application domain. Every request in application has an identity associated; it could be the user who is connected or impersonating any other user’s identity.

With the enhancement in the .NET Framework there has been significant change with in the framework to handle the security either it is windows based authentication or form authentication, but Identity is again at the center in both the authentications. Both are derived from IIdentity interface.

New release of .NET Framework (v 4.5) is bringing the significant change in the way Identity has been maintained; basically the new framework has changed the definition of identity. Now Identity just doesn’t describes the user on whose behalf the code is running but also provide the richer/detailed (Claim) information about the identity and it can provide more granular control on Authentication and Authorization.

with above progression .NET Identity can be divided in to two era.

  1. Pre-claims in .NET 1.0 – 4.0
  2. Post-claims in .NET 4.5

 Identity in .NET 1.0-

.NET Released in 2002 –

Identity was part of the .NET Framework 1.0 and it was designed based on the security concepts or features in late 1990s. It was also very centric to Windows users and groups to identify and authenticate users.

A Look on IIdentity and IPrincipal –

Based on definition –

IIdentity represent who the user is

IPrincipal is what a user can do (Roles)

namespace System.Security.Principal
{
   public interface IIdentity
   {
       bool   IsAuthenticated    { get; }
       string Name               { get; }
       string AuthenticationType { get; }
   }
   public interface IPrincipal
   {
       IIdentity Identity { get; }
       bool IsInRole(string role);
   }
}

 Identity v1.0 isn’t enough

If you carefully look at the properties of IIdentity and IPrincipal it has basically two properties

  1. Name  – This provides the name of the current user
  2. IsInRole – A binary function to identify it the user is part of a group or not (Admin vs. not admin)

As I said they Identity is designed based on the requirement of late 1990 and not the current era and it doesn’t satisfy the need of the current scenarios like what is my important attributes like email or something else related to business domain; for example, can I transfer money from my account (Role=Transfer) but can I transfer $ 1000 or more in a day or maybe I am a privilege user and can transfer more than $1000 when my account balance is more than $10000 on that day.

Where does Identity comes from

Or who are my identity providers, it be can be anyone like Active Directory, Application based database to provide the identity or if a business organization whom I am part of but also working with sister company.

Claims-Based Authentication –

This allows application to outsource the authentication logic to a provider (Identity Provider or IP). An IP could be within the organization or a third party provider (like Google), IP hides all the details about authentication logic and provide a simple contract that dictate that user is authenticated or not and if authenticated then information (Claims) about user.

Claims as a better Identity

Definition wise – A claim is a statement about a subject by an issuer. Here claim is properties of the user like “I can transfer $1000 on any day”, where user is the subject and issuers is the authority that provides the claim as part of my identity; in this case my bank is the identity provider who issued certain claims to me to perform certain operation.

Object representation of Claim – Claim consists of 3 properties, issuer, type and value.

namespace System.IdentityModel.Claims
{
   public class Claim
   {
       public string ClaimType { get; }
       public object Resource { get; }
       public string Right { get; }
   }
}

Identity in .NET 4.5

There is has been significant structural changes in the way .NET handles the security. Now claims are the very basic foundation of .NET Security. Now ClaimsIdentity directly implements the good old IIdentity interface and all other Identity (windows, generic, form) derived from ClaimsIdentity. Similarly, ClaimsPrincipal directly implements the IPrincipal Interface and all other principal classes inherit from ClaimsPrincipal.

Identity4.5

Claims and Kerberos

As Claims are integrated now with every Identity type you can access them anywhere. E.g. below example demonstrates Claims integrated into Kerberos (WindowsIdentity).

static void Main(string[] args)
{
       var id = WindowsIdentity.GetCurrent();
       foreach (var claim in id.Claims)
       {
           Console.WriteLine("{0}, {1}", claim.Type, claim.Value);
       }
}

 Beyond Claims

Following are the features provided by WIF programming model.

  1. Credential types
  2. Claims transformation
  3. Claims-based authorization
  4. Session management
  5. Federation

 Credential Types

The advantage with Claims Model is that Application is independent of the authentication logic and will be out of business to handle the security token getting generated as part of the authentication, all your application care is Claims.

Authentication will be handled by WIF provided module or a third party Identity Provider (STS). There are different type of security token gets generated based on the mechanism we choose to trust/develop the Identity Provider.

  1. AD or Kerberos
  2. FormAuthentication
  3. Certificates
  4. SAML Token

WIF has an abstract class SecurityTokenHandler to process the token and it also has different implementation to handle the security token and they are responsible to handle and process the incoming tokens and get the claims in the in ClaimsPrincipal for respective security token handler.

  • Saml2SecurityToken
  • SamlSecurityToken
  • KerberosRequestorSecurityToken
  • KerberosReceiverSecurityToken
  • RsaSecurityToken
  • SessionSecurityToken
  • UserNameSecurityToken
  • WindowsSecurityToken
  • X509SecurityToken
  • X509WindowsSecurityToken

Above classes are specific implementation to handle specific security tokens, like Windows SecurityToken handles the windows domain account.

Claims Transformation –

Identity information in token not always enough, every application has some specific requirement which requires application to add, remove, transform and/or reject claims.

WIF provides ‘ClaimsAuthenticationManager’ pipeline to calling application to transform the claims based on its requirement.

public class CustomClaimsAuthenticationManager : ClaimsAuthenticationManager
{
	public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal 										incomingPrincipal)
	{
		if (incomingPrincipal.Identity.IsAuthenticated)
		{
			 return TranformClaims(incomingPrincipal);
		}
		return incomingPrincipal;
	}
 }

Sessions

Once Authenticated from IP or STS, application receives the secured token along with Claims and they will be serialized to store in cache or cookie along with application specific claims to avoid the processing to application specific claims again and again.

Cookie in ASP.NET and WS-SecureConversation in WCF can be used as storage for claims.

var sam = FederatedAuthentication.SessionAuthenticationModule;
if (sam != null)
{
       var token = new SessionSecurityToken(ClaimsPrincipal.Current, TimeSpan.FromHours(8));
       sam.WriteSessionTokenToCookie(token);
}

Implement Authorization

Once user is authorized, its application responsibility to perform the Authorization, WIF provided ClaimsAuthorizationManager is base class to perform the authorization in the application, all you need is to derive an implementation of it.

ClaimsAuthorizationManager provides the centralized and decoupled authorization for application. Authorization can be perform based on User making a request, a resource being accessed or any action being performed.

public class CustomClaimsAuthorization : ClaimsAuthorizationManager
{
    public override bool CheckAccess(AuthorizationContext context)
    {
           var user = context.Principal;
           var resource = context.Resource.First().Value;
           var action = context.Action.First().Value;
           if (resource == "Customer" && action == "Add")
           {
	      return user.HasClaim(ClaimTypes.Role, "Sales");
           }
           return base.CheckAccess(context);
    }
}

Federation

In federation applications are decoupled from authentication and Federation Provider (IP or STS) is responsible to manage the identity and issues the claims which are requested/application for application (relying party). Because application trust the IP for identity, in certain scenario, it is also possible that an IP itself rely on another IP for authentication. This facilitate SSO between multiple application if they trust the claims issued from a IP or STS.

Federation

What is behind WIF

There are few basic components which makes all the magic behind WIF.

Federation Metadata – This is a XML file which contains the entire security requirement that a client application needs to know to a build a trust; this includes security protocol you expect, which claims your application requires and so on.

WSFederationAuthenticationModuleOften called as WSFAM, provides most of the functionality, like intercepting request and redirect unauthenticated requests to identity providers and processing of incoming tokens at sign in time.

SessionAuthenticationModuleOften referred as SAM. Once authenticated this module is responsible for session management and all subsequent request will be processed by SAM until the session expire or sign out.

ClaimsAuthorizationModule – This module is responsible for enforcing authorization policies on every request. A sample implementation is covered earlier.

How it works

WIF sits infront in the asp.net processing pipeline and when it sees an unauthenticated request it redirect that request to IP for authentication (Handled by WSFAM), its upto IP to decide about the mechanism to authenticate the user, it could be validating through a login page or kerberos.

After authentication, it issues a secure token containing claims. Now WIF takes this secure token and drops a cookie and established the session.

Identity Provider (IP) or STS

An IP is an entity which knows about subject (user), it knows how to authenticate them and provides claims associated with subject once requested on successful authentication.

IP implementation varies and two variation available currently are Passive and Active. In passive scenario relying party or application redirect user to login page hosted in STS. In active scenario relying party application uses WSTrust protocol to connect with STS and request for secured token.

Though Visual Studio provides ways to implement STS but it is not advisable to create a custom STS, as STS is responsible for handling security specific transaction, and any loop hole in the STS can make organization vulnerable. A STS considered well only when it is secure, available, and high performing and manageable. There are commercial STS are available and it is advised to use them as they are secured and tested. Some of these products are:

  1. Active Directory Federation Services (ADFS) v2
  2. IBM Tivoli Federation Manager
  3. Oracle Identity Manager 

That’s all from the introduction point of view. You will find many example of STS on internet specially passive STS. I am currently working on to build an active STS and I will write about it next time.

Posted in Security, WIF | Tagged , | 2 Comments

Tutorials – Introduction to ASP.NET MVC

For past few days, I have been training folks in my organization on ASP.NET MVC. I have uploaded the presentation from the session here – http://sdrv.ms/Xk1TrU

Do let me know your feedback and check it frequently as I will be updating the document based on further trainings and feedback.

Thanks,

Posted in MVC, Speaking | Tagged , | Leave a comment

Custom Error Handling in ASP.NET MVC

This post covers custom error and exception handling in ASP.NET MVC with more generic approach to satisfy the need of today’s development, today’s development doesn’t mean that we are going to handle the error in a different way than currently supported by MVC but handling error slightly different to allow more responsive and user friendly UI.

If you are looking for ASP.NET MVC in-built exception handling then this post may not cover it in its entirety. You will get several other posts talking about MVC exception handling in much better way. I prefer MVC’s HandleErrorAttribute with some customization to handle all Http 500 errors, anything beyond 500 has to be handled by Application’s Error event. I prefer to outsource Application level error handling to a common Http Module; it can be plugged in to any application by some generic implementation and configuration.

MVC’s default HandleErrorAttribute is really good and serves all purpose for a good basic exception handling mechanism but it requires customization, if you need to perform logging or action action.

Scenario

The goal of this post is to handle a complex scenario where a single view might have multiple child views rendered like header, footer, carousel, multiple widgets, and scenario like content managed websites. Let’s talk about from the user perspective, who is trying to visit your site, for him the most important stuff is his business with your site, he may not be interested in weather an widget appearing at the corner of your site or any other less concerning area. He comes to your site and suddenly the weather widget fails, it could be due to your weather service provider being down or some network issue or any other reason but as the action method responsible to display the weather information fails, your standard error handling mechanism will take him to standard error page. You can argue that I will add a try catch block to handle the error and display a custom error message to the user but if you have got 5 widgets then you need to do the same for every action method, repeating the same code every time with different error message not to mention it will become more difficult in content managed environment.

A better way to handle it

To find a better way, we need to identify what is important for user and what is less important. Something important will always take user to Error Page and less important will make the page to render with custom message or possible remove the view or it would be better if it replaces the view with some other view.

Building Blocks

Let’s talk in terms of MVC, we will still use the IExceptionFilter or HandleError with some customization to achieve it, but first we will identify what we want to do in different scenarios.

1) Redirect – Most important and default behavior required for system.

2) Replace – Important but can be replaced by a different view.

3) ShowError – Less important, pages can render without any issue and failed widgets will display custom messages

4) Hide – Least important, erred area or view can be removed from the page.

Now an enum is required to handle these scenarios.

    ///
    /// ActionType
    ///
    public enum ActionType
    {
       ///
       /// Redirect will abort the execution of current page will redirect to an error page
       ///
       Redirect = 0,

       ///
       /// Replace the view with a different view
       ///
       Replace = 1,

       ///
       /// ShowError will show the custom error message
       ///
       ShowError = 2,

       ///
       /// Hide will hide the custom error message and display empty result
       ///
       Hide = 3
}

Error Model to pass the error information and custom message to the view

   
    ///
    /// ErrorModel
    /// A custom error model class to pass the error info
    ///
    public class ErrorModel : HandleErrorInfo 
    { 
       ///
       /// Displayable error message 
       ///
       public string ErrorMessage { get; set; } 

       public ErrorModel(string errorMessage, Exception exception, string controllerName, string actionName) :base(exception, controllerName, actionName) 
      { 
           this.ErrorMessage = errorMessage; 
      } 
    }

Now we have the scenarios covered but we also need to modify the HandleError attribute to handle these scenarios. For brevity, I will implement the interface IExceptionFilter than customizing the HandleError attribute.

     ///
     /// HandleExceptionAttribute
     /// Represents an attribute that is used to handle an exception that is thrown by an action method.
     ///
     [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]   
     public class HandleExceptionAttribute : FilterAttribute, IExceptionFilter 
     {

Some default behavior, it is mostly copied from HandleError attribute –

 
        private Type exceptionType = typeof(Exception);

        private readonly string defaultView = "Error";

        private string view = string.Empty;

        ///
        /// ExceptionType
        ///
        public Type ExceptionType
        { 
            get { return this.exceptionType; } 
            set 
            { 
                   if (value == null) 
                   { 
                       throw new ArgumentNullException("value"); 
                   } 
                   if (!typeof(Exception).IsAssignableFrom(value))
                   { 
                       throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "The type {0} does not inherits from the exception", new object[] { value.FullName })); 
                   } 
                   this.exceptionType = value; 
            } 
        } 
        ///
        /// ErrorId 
        /// Error Id to be initialize with Attribute and will be used to call the content service to fetch the appropriate error message. 
        ///
        public string ErrorId { get; set; } 

        ///
        /// Action 
        ///
        public ActionType Action { get; set; } 

        ///
        /// View 
        ///
        public string View 
        { 
           get 
           { 
                if (string.IsNullOrEmpty(this.view)) 
                { 
                     return defaultView; 
                } 
                return this.view; 
           } 
           set 
           {  
                this.view = value; 
           } 
        }

Add the interfaces to handle the logging and Error Message retrieval from content store (config or db), an implementation of IContentService is required to get the message from content store.

     

        #region Properties to handle logging and content retrieval 

        ///
        /// Logger
        /// To log the error messages or any other diagnostic information
        ///
        public ILogger Logger { get; set; } 

        ///
        /// Content Service 
        /// Content Service to retrieve the content from Config or DB 
        ///
        public IContentService ContentService { get; set; } 

        #endregion

Initialization

       

       #region Constructor

        ///
        /// Initializes a new instance of the HandleExceptionAttribute class.
        ///
        public HandleExceptionAttribute() 
             : this(DependencyResolver.Current.GetService(), DependencyResolver.Current.GetService()) 
        { } 
         
        ///
        /// Initializes a new instance of the HandleExceptionAttribute class. 
        ///
        public HandleExceptionAttribute(ILogger logger, IContentService contentService) 
        { 
           this.Logger = logger; 
           this.ContentService = contentService;
        } 
        
        #endregion

Exception Handler

Most of the stuff in OnException method is similar to HandleError except the logic to handle the scenario. This logic is built on the assumption that your individual views are partial view and ShowError and Replace will just swap the view. There will be some customization required to view to display it in the right format as all the views may not be of same size.

Keeping the highest priority in mind, this attribute default the behavior to redirect and in case of nothing specified it will redirect to default error page mentioned in the customError section inside web.config file.


       ///
       /// Called when an exception occurs.
       ///
       public virtual void OnException(ExceptionContext filterContext) 
       { 
            // Bail if we can't do anything; propogate the error for further processing. 
            if (filterContext == null) 
                 return; 
            if (!filterContext.ExceptionHandled &amp;&amp; filterContext.HttpContext.IsCustomErrorEnabled) 
            { 
                Exception innerException = filterContext.Exception; 
                if ((new HttpException(null, innerException).GetHttpCode() == 500) &amp;&amp; this.ExceptionType.IsInstanceOfType(innerException)) 
                { 
                      string controllerName = (string) filterContext.RouteData.Values["controller"]; 
                      string actionName = (string) filterContext.RouteData.Values["action"]; 
                      // Log exception Logger.Log(innerException.Message); 
                      switch (this.Action) 
                      { 
                             case ActionType.ShowError: 
                                   var errorModel = new ErrorModel(ContentService.GetErrorMessage(this.ErrorId), filterContext.Exception, controllerName, actionName); 
                                   filterContext.Result = new ViewResult { ViewName = this.View, ViewData = new ViewDataDictionary(errorModel), TempData = filterContext.Controller.TempData }; 
                                   break; 
                             case ActionType.Hide: 
                                   filterContext.Result = new EmptyResult(); 
                                   break; 
                             case ActionType.Replace: 
                                   // a logic similar to ShowError required to replace the view 
                                   break; 
                             default: 
                                   var errorSection = ConfigurationManager.GetSection("system.web/customErrors") as CustomErrorsSection; 
                                   filterContext.Result = new RedirectResult(errorSection.DefaultRedirect);          
                                   break; 
                      } 
                      filterContext.ExceptionHandled = true; 
                      filterContext.HttpContext.Response.Clear(); 
                      filterContext.HttpContext.Response.StatusCode = 500;
                      filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; 
                 }
            } 
       }

Example

Below example will take the default behavior of handle exception attribute and redirect to error page, which can have default or standard error message.


        [HandleException()]
        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

Below example will take the action type as show error and will call the content service to get the standard error message based on the error id specified and render the custom view with the error message.


         [HandleException(Action = ActionType.ShowError, ErrorId = "ErrId1", View = "CustomError", ExceptionType = typeof(ArgumentNullException))]
        public ActionResult About()
        {
            if (User.Identity == null)
                throw new ArgumentNullException("Null Identity");
            return View();
        }
Posted in MVC | Tagged , | 3 Comments

A simple Pdf ActionResult in MVC

Recently, I needed an ActionResult implementation to return the Pdf documents from my Controller Action to MVC views and it tooks few minutes to build the functionality on the existing FileResult.

I decided to build a base class PdfResult to abstract the ContentType implementation as well as it will also serve as a common return type from the action method irrespective of derived implementation like Content, Path etc.

PdfResult Base class

///
/// PdfResult
/// Represents a base class that is used to send PDF file content to the response.
public abstract class PdfResult : FileResult
{
    #region Constructor
     ///
     /// Initializes a new instance of the FileResult class.
     ///

    public PdfResult()
      : base(System.Net.Mime.MediaTypeNames.Application.Pdf)
    {
    }

    #endregion
}

PdfStreamResult It’s one of the implementation class for PdfResult to return the Pdf content as stream on HttpResponse Stream.

///
/// PdfStreamResult
/// Sends binary content to the response by using a Stream instance.
///
public class PdfStreamResult : PdfResult
{
    // Fields
    private const int _bufferSize = 0x1000;

    #region Constructor

    ///
    /// PdfContentResult
    /// Initializes a new instance of the FileStreamResult class.
    ///
    public PdfStreamResult(Stream fileStream)
       : base()
    {
         if (fileStream == null)
         {
             throw new ArgumentNullException("fileStream");
         }
         this.FileStream = fileStream;
    }

    #endregion

    #region Overriden Methods

    ///
    /// WriteFile
    /// Writes the file to the response. (Overrides FileResult.WriteFile(HttpResponseBase).)
    protected override void WriteFile(HttpResponseBase response)
    {
         Stream outputStream = response.OutputStream;
         using (this.FileStream)
         {
              byte[] buffer = new byte[0x1000];
              while (true)
              {
                   int count = this.FileStream.Read(buffer, 0, 0x1000);
                   if (count == 0)
                   {
                       return;
                   }
                   outputStream.Write(buffer, 0, count);
              }
         }
     }

    #endregion

     ///
     /// FileContents
     /// Gets the stream that will be sent to the response.
     public Stream FileStream { get; private set; }
}

PdfPathResult

This implementation class return the Pdf document from a physical Pdf file on the server.


///
/// PdfPathResult
/// Sends the contents of a file to the response.
public class PdfPathResult : PdfResult
{
    #region Constructor

    ///
    /// PdfContentResult
    /// Initializes a new instance of the FilePathResult class by using the specified file name and content type.
    ///
    public PdfPathResult(string fileName)
         : base()
    {
        if (string.IsNullOrEmpty(fileName))
        {
            throw new ArgumentException("Value cannot be null or empty.", "fileName");
        }
        this.FileName = fileName;
    }

    #endregion

    #region Overriden Methods

     ///
     /// WriteFile
     /// Writes the file to the response. (Overrides FileResult.WriteFile(HttpResponseBase).)
     protected override void WriteFile(HttpResponseBase response)
     {
          response.TransmitFile(this.FileName);
     }

     #endregion

     ///
     /// FileContents
     /// Gets the path of the file that is sent to the response.
     public string FileName { get; private set; }
  }

PdfContentResult

This implementation returns the Pdf document out of binary content of Pdf document.


///
/// PdfContentResult
/// Sends the contents of a binary file to the response.
///
public class PdfContentResult : PdfResult
{
    #region Constructor

    ///
    /// PdfContentResult
    /// Initializes a new instance of the PdfContentResult class by using the specified file contents and content type.
    ///
    public PdfContentResult(byte[] fileContents)
        : base()
    {
        if (fileContents == null)
        {
            throw new ArgumentNullException("fileContents");
        }
        this.FileContents = fileContents;
    }

    #endregion

    #region Overriden Methods

    ///
    /// WriteFile
    /// Writes the file content to the response. (Overrides FileResult.WriteFile(HttpResponseBase).)
    protected override void WriteFile(HttpResponseBase response)
    {
      response.OutputStream.Write(this.FileContents, 0, this.FileContents.Length);
    }

    #endregion

    ///
    /// FileContents
    /// The binary content to send to the response.
    public byte[] FileContents { get; private set; }
  }

Controller Extensions

I needed to write these extension to have the calling code look similar to ViewResult or other result types.


///
/// Defines extensions for controllers
public static class ControllerExtensions
{
   #region Pdf Extension method for Controller

   ///
   /// Pdf
   /// Creates a PdfContentResult object by using the file contents, content type, and the destination file name.
   /// The Controller
   /// The binary content to send to the response.
   /// The file name to use in the file-download dialog box that is displayed in the browser.
   /// The file-content result object.
   public static PdfResult Pdf(this Controller controller, byte[] fileContents, string fileDownloadName)
   {
      return new PdfContentResult(fileContents) { FileDownloadName = fileDownloadName };
   }

   ///
   /// Pdf
   /// Creates a PdfStreamResult object using the Stream object, the content type, and the target file name.
   /// The Controller
   /// The stream to send to the response.
   /// The file name to use in the file-download dialog box that is displayed in the browser.
   /// The file-stream result object.
   public static PdfResult Pdf(this Controller controller, Stream fileStream, string fileDownloadName)
   {
       return new PdfStreamResult(fileStream) { FileDownloadName = fileDownloadName };
   }

   ///
   /// Pdf
   /// Creates a PdfPathResult object by using the file name, the content type, and the file download name.
   /// The Controller
   /// The path of the file to send to the response.
   /// The file name to use in the file-download dialog box that is displayed in the browser.
   /// The file-stream result object.
   public static PdfResult Pdf(this Controller controller, string fileName, string fileDownloadName)
   {
        return new PdfPathResult(fileName) { FileDownloadName = fileDownloadName };
   }

   #endregion
}

Example

PdfStreamResult

public PdfResult DownloadPdf()
{
   Stream fileStream = ...; //initialization code to initialize the stream with Pdf File.
   return this.Pdf(fileStream, "Sample.pdf");
}

PdfPathResult


public PdfResult DownloadPdf()
{
    string filePath = ; //initialization code to initialize the string with Pdf File Path.
    return this.Pdf(filePath, "Sample.pdf");
}

PdfContentResult


public PdfResult DownloadPdfContent()
{
    string filePath = ; //initialization code to initialize the string with Pdf File Path.
    byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
    return this.Pdf(pdfBytes, "sample.pdf");
    return pdfContent;
}
Posted in MVC | Tagged , | 13 Comments