European ASP.NET MVC Hosting

BLOG about Latest ASP.NET MVC Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET MVC 4 Hosting - Amsterdam :: Implementing a Custom IPrincipal in ASP.NET MVC 4 Internet Project

clock April 16, 2013 10:49 by author Scott

This article explains a simple tip on how to customized the IPrincipal used in ASP.NET MVC4 internet application project template. You can try this tip if you want to attach additional information on the IPrincipal (Controller.User) for some purposes.

This tip is based from the solution I used in implementing custom identity in my ASP.NET MVC 3 project which I got from this thread: http://stackoverflow.com/questions/1064271/asp-net-mvc-set-custom-iidentity-or-iprincipal.

The main solution is almost the same from the said thread but with just a few tweaks required to set data to additional IPrincipal properties when OAuthWebSecurity is used as authentication method.  

Initially ASP.NET MVC 4 internet project template is configured to use both WebMatrix.WebSecurity (for local accounts) and OAuthWebSecurity (for external site accounts) for authentication. Also accounts data are getting saved in a UserProfile table which only have properties for user ID and username, and some predefined webpages_TABLES. 

This initial setup is not enough for us to achieve our goal: that is to attach additional information in the IPrincipal. In this example we will going to need to add the first name and last name info of the user but you can add any data to suit your needs.

We will need first a storage of the additional data we want to attach. To do this you can just simply add properties on the UserProfile class defined in AccountModels.cs. Or use any table then modify the InitializeSimpleMembershipAttribute.cs from the Filters folder and set your DBContext and table name:

public SimpleMembershipInitializer()
{
    Database.SetInitializer<YourDBContext>(null);

    try
    {
      using (var context = new UsersContext())
      {
        if (!context.Database.Exists())
        {
          // Create the SimpleMembership database without Entity Framework migration schema
          ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
        }
      }

      WebSecurity.InitializeDatabaseConnection("DefaultConnection", "YourDesiredTable",
              "UserId", "UserName", autoCreateTables: true);
    }
    catch (Exception ex)
    {
      throw new InvalidOperationException("The ASP.NET Simple Membership database could " +
        "not be initialized. For more information, please see " +
        "http://go.microsoft.com/fwlink/?LinkId=256588", ex);
    }
}

Another way is to leave the SimpleMembershipInitializer as it is and check this tutorial: http://www.asp.net/mvc/tutorials/mvc-4/using-oauth-providers-with-mvc 

If your data storage is now ready we can now start creating custom IPrincipal: 

public interface ICustomPrincipal : System.Security.Principal.Iprincipal
{
    string FirstName { get; set; }

    string LastName { get; set; }
}
public class CustomPrincipal : IcustomPrincipal
{
    public IIdentity Identity { get; private set; }

    public CustomPrincipal(string username)
      {
            this.Identity = new GenericIdentity(username);
      }

      public bool IsInRole(string role)
      {
            return Identity != null && Identity.IsAuthenticated &&
               !string.IsNullOrWhiteSpace(role) && Roles.IsUserInRole(Identity.Name, role);
      }

      public string FirstName { get; set; }

      public string LastName { get; set; }

      public string FullName { get { return FirstName + " " + LastName; } }
}

public class CustomPrincipalSerializedModel
{
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}

Then in the AccountController class, add this method. We will need this method to serialize the user data and attach it in a cookie: 

public void CreateAuthenticationTicket(string username) {      

      var authUser = Repository.Find(u => u.Username == username); 
      CustomPrincipalSerializedModel serializeModel = new CustomPrincipalSerializedModel();     

      serializeModel.FirstName = authUser.FirstName;
      serializeModel.LastName = authUser.LastName;
      JavaScriptSerializer serializer = new JavaScriptSerializer();
      string userData = serializer.Serialize(serializeModel);     

      FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
        1,username,DateTime.Now,DateTime.Now.AddHours(8),false,userData);
      string encTicket = FormsAuthentication.Encrypt(authTicket);
      HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
      Response.Cookies.Add(faCookie);
}

Call the above method: From the ExternalLoginCallback method: 

public ActionResult ExternalLoginCallback(string returnUrl)
{
      AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
        Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
      if (!result.IsSuccessful)
      {
        return RedirectToAction("ExternalLoginFailure");
      }

      if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: true))
      {
        CreateAuthenticationTicket(OAuthWebSecurity.GetUserName(
                        result.Provider, result.ProviderUserId));
        return RedirectToLocal(returnUrl);
      }

      if (User.Identity.IsAuthenticated)
      {
        // If the current user is logged in add the new account
        OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
        CreateAuthenticationTicket(User.Identity.Name);
        return RedirectToLocal(returnUrl);
      }
      else
      {
        // User is new, ask for their desired membership name
        string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
        ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
        ViewBag.ReturnUrl = returnUrl;
        return View("ExternalLoginConfirmation",
          new RegisterExternalLoginModel { UserName = result.UserName, ExternalLoginData = loginData });
      }
}

In Register method: 

public ActionResult Register(RegisterModel model)
{
  if (ModelState.IsValid)
  {
    // Attempt to register the user
    try
    {
      WebSecurity.CreateUserAndAccount(
        model.UserName,
        model.Password,
        new {            
            UpdatedBy = 0,
            UpdatedDate = DateTime.Today,
            CreatedBy = 0,
            CreatedDate = DateTime.Today
          }
       );

      WebSecurity.Login(model.UserName, model.Password);
      CreateAuthenticationTicket(model.UserName);
      return RedirectToAction("Index", "Home");
    }
    catch (MembershipCreateUserException e)
    {
      ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
    }
}

In ExternalLoginConfirmation method: 

...
OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
 OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
 CreateAuthenticationTicket(model.UserName);
 return RedirectToLocal(returnUrl);   
... 

And in the Login method: 

public ActionResult Login(LoginModel model, string returnUrl)
{
      if (ModelState.IsValid && WebSecurity.Login(model.UserName,
                model.Password, persistCookie: model.RememberMe))
      {
        CreateAuthenticationTicket(model.UserName);
        return RedirectToLocal(returnUrl);
      }

      // If we got this far, something failed, redisplay form
      ModelState.AddModelError("", "The user name or password provided is incorrect.");
      return View(model);
}

It's now time to read the serialized data from our cookie and replace the HttpContext.Current.User. Do this by overriding the Application_PostAuthenticateRequest method in project's Global.asax.cs . 

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
      HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
      if (authCookie != null)
      {
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        if (authTicket.UserData == "OAuth") return;
        CustomPrincipalSerializedModel serializeModel =           serializer.Deserialize<CustomPrincipalSerializedModel>(authTicket.UserData);
        CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
        newUser.Id = serializeModel.Id;
        newUser.FirstName = serializeModel.FirstName;
        newUser.LastName = serializeModel.LastName;
        HttpContext.Current.User = newUser;
      }
}

To access the attached data from pages:

@(User as CustomPrincipal).FullName

And from server: 

@(User as CustomPrincipal).FullName



European ASP.NET MVC 4 Hosting - Amsterdam :: How to Add Metatags on .cshtml Pages in MVC

clock April 8, 2013 09:08 by author Scott

This quick article is a response to a question I received today on Facebook. Please use the following procedure to add metatags on .cshtml pages.

Step 1

When we create a MVC4 Application using an Internet Template we get a "Shared" folder inside the "Views" folder on the root and in the "Shared" folder you will find a layout page named "_Layout.cshtml". Open that file.

Step 2

In the "_Layout.cshtml" page add a new section call inside the <head> tag, as given below:

In the above image you can see that a section call is not required; in other words whenever we need metatags on a page we can define.

Step 3

Now, open you .cshtml page where you wish to add metatags and add the following section reference:

Step 4

Now, open the page in a browser and you will see your metatags in action.

Advanced

We can also make these metatags dynamic, in other words we can control them from controllers.

Controller

public ActionResult Index()
{
    ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
    ViewBag.MetaKeywords = "abc";
    ViewBag.MetaDescription = "abc";

    return View();
}

Section on .cshtml page

@section metatags {
    <meta name='keywords' content='@ViewBag.MetaKeywords'/>
    <meta name='description' content='@ViewBag.MetaDescription'/>
}

Hope this helps.

 



European ASP.NET MVC 4 Hosting - Amsterdam :: Using NHibernate in an ASP.NET MVC 4 Application

clock March 6, 2013 05:58 by author Scott

ASP.NET MVC is a common framework for developing web applications. As we all know that M in MVC stands for model, and for a Line of business (LoB application ), the model is often the backbone. For defining a model that persists in a database, ASP.NET MVC supports Entity Framework (now Open Source) out of the box. Other possible options are:

ADO.NET hand coded data layer where you write all the queries explicitly.

- Use commercial O/R mappers like LLBLGen
- Use Open Source O/R mapper like NHibernate.

Today we will see how we can get started using Nhibernate

Getting Started with NHibernate

You can get additional information about the NHibernate from here.

Once you identify various models and relationship in your data model, you can now introduce NHibernate for mapping these models to a persistence store like (SQL Server, Oracle etc).
One of the most important part of using ORM is establishing mapping between Model objects and the Database tables. If we use NHibernate, then this mapping needs to be set explicitly using XML file.

In the following steps, we will be exploring use of NHibernate in ASP.NET MVC 4 application.

Step 1: Open VS 2012 and create MVC 4 application. On the project, right click and select  Manage NuGet Packages’. You will see the Manage Nuget Packages screen. In the search TextBox enter ‘NHibernate’ and you will get the following result:

Once you click the ‘Install’, you will get below references in then project:

- NHibernate
- Lesi.Collections

Step 2: Now it is a time to define the Model layer. As I wrote in the beginning that based upon the application requirement, you need to decide upon the Model objects and the relationship between them. So now let’s define an application that is used to maintain employee records (very simple, but you can extend the concept). Let’s add the new class in the Models folder as shown below:

public class EmployeeInfo
{
int _EmpNo;
public virtual int EmpNo
{
  get { return _EmpNo; }
  set { _EmpNo = value; }
}
string _EmpName;
public virtual string EmpName
{
  get { return _EmpName; }
  set { _EmpName = value; }
}
int _Salary;
public virtual int Salary
{
  get { return _Salary; }
  set { _Salary = value; }
}
string _DeptName;
public virtual string DeptName
{
  get { return _DeptName; }
  set { _DeptName = value; }
}
string _Designation;
public virtual string Designation
{
  get { return _Designation; }
  set { _Designation = value; }
}
}

The class EmployeeInfo contains properties. These properties will be used for mapping with the Table Columns. These properties are defined as virtual properties because of the lazy association which is used by NHibernate to set proxy entity on association property.

Step 3: Once the Model class for mapping is ready, now let’s think of the database to persist the data. For this simple application, we will use a database called Company in SQL Server. The name of the table is EmployeeInfo which can be created as shown below:

USE [Company]
GO
/****** Object:  Table [dbo].[EmployeeInfo]    Script Date: 1/17/2013 11:22:12 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[EmployeeInfo](
    [EmpNo] [int] IDENTITY(1,1) NOT NULL,
    [EmpName] [varchar](50) NOT NULL,
    [Salary] [decimal](18, 0) NOT NULL,
    [DeptName] [varchar](50) NOT NULL,
    [Designation] [varchar](50) NOT NULL,
CONSTRAINT [PK_EmployeeInfo] PRIMARY KEY CLUSTERED
(
    [EmpNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING
OFF
GO

Step 4: To set the mapping, we need to add an XML file in the project as ‘Embedded Resource’. For this sample, I’ll use two folders under the default Model folder - NHibernate\Configuration and NHibernate\Mappings.

The naming convention for the mapping files are by default <ModelName>.hbm.xml, so in our case it will be ‘EmployeeInfo.hbm.xml’. This file goes into the Mappings folder. This file maps the Model class with the database table columns with the constraints like primary key, data types etc. The file is as shown below:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="MVC4_Using_NHB"
namespace="MVC4_Using_NHB"
auto-import="true">
<class name="MVC4_Using_NHB.Models.EmployeeInfo,MVC4_Using_NHB">
  <id name="EmpNo" access="property" column="EmpNo" type="Int32">
   <generator class="native"></generator>
  </id>
  <property name="EmpName" access="property"
   column="EmpName" type="String"></property>
  <property name="Salary" access="property"
   column="Salary" type="Int32"></property>
  <property name="DeptName" access="property"
   column="DeptName" type="String"></property>
  <property name="Designation" access="property"
   column="Designation" type="String"></property>
  </class>
</hibernate-mapping>


The above xml file demonstrates the mapping between EmployeeInfo class and its properties with the columns. The mapping table is defined by the NHibernate APIs while establishing connection to database.

Note: One important thing is that by default no intellisense is available so to achieve this add nhibernate-configuration.xsd and nhibernate-mapping.xsd in below path

C:\Program Files (x86)\Microsoft Visual Studio 11.0\Xml\Schemas

Step 5: Once the mapping is defined, now let’s define the NHibernate configuration for the application. This provides information about the database provider, connection string and the mapping file used for the connectivity. So in the project, add a new XML file in the Models\Configuration folder created above; the name of the file will be ‘hibernate.cfg.xml’. Add the following configuration in it:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
  <property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider</property>
  <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
  <property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver</property>
  <property name="connection.connection_string">Data Source=.;Initial Catalog=Company;Integrated Security=SSPI</property>
  <property name="show_sql">false</property>
</session-factory>
</hibernate-configuration>


Step 6: Now it’s time to add some code to do CRUD operations against the database table using the mapping model. NHibernate provides various classes and interfaces for performing operations, some of them are used in this implementation and they are as below:

ISession: This is a main runtime interface between NHibernate and .NET and is used to manipulate entities.

ISessionFactory: A Session is created by this interface. The method ‘OpenSession()’ is provided to create session. One session factory is required per database. The implementation is thread safe and can live till the life time of the application.

As you can see in the code below, we have provided the absolute path of the configuration file to the configuration object and also provided it with the Directory Information where all the mapping files will be kept (in the OpenSession method).

IQuery: This is an object representation of NHibernate query. This is created using ‘CreateQuery()’ method of the ISession. This is the method where the table name is passed and based upon which column the mapping can take place.

ITransaction: Used to manage transactions. This is required during DML operations.
Add a new class in the Models folder and add the following code in it:

/// <summary>
/// class to perform the CRUD operations
/// </summary>
public class EmployeeInfoDAL
{
//Define the session factory, this is per database
ISessionFactory sessionFactory;
/// <summary>
/// Method to create session and manage entities
/// </summary>
/// <returns></returns>
ISession OpenSession()
{
  if (sessionFactory == null)
  {
   var cgf = new Configuration();
   var data = cgf.Configure(
         HttpContext.Current.Server.MapPath(
            @"Models\NHibernate\Configuration\hibernate.cfg.xml"));
   cgf.AddDirectory(new System.IO.DirectoryInfo(
         HttpContext.Current.Server.MapPath(@"Models\NHibernate\Mappings")));
   sessionFactory = data.BuildSessionFactory();
  }
  return sessionFactory.OpenSession();
}
public IList<EmployeeInfo> GetEmployees()
{
  IList<EmployeeInfo> Employees;
  using (ISession session = OpenSession())
  {
   //NHibernate query
   IQuery query = session.CreateQuery("from EmployeeInfo");
   Employees = query.List<EmployeeInfo>();
  }
  return Employees;
}
public EmployeeInfo GetEmployeeById(int Id)
{
  EmployeeInfo Emp = new EmployeeInfo();
  using (ISession session = OpenSession())
  {
   Emp = session.Get<EmployeeInfo>(Id);
  }
  return Emp;
}
public int CreateEmployee(EmployeeInfo Emp)
{
  int EmpNo = 0;
  using (ISession session = OpenSession())
  {
   //Perform transaction
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Save(Emp);
    tran.Commit();
   }
  }
  return EmpNo;
}
public void UpdateEmployee(EmployeeInfo Emp)
{
  using (ISession session = OpenSession())
  {
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Update(Emp);
    tran.Commit();
   }
  }
}
public void DeleteEmployee(EmployeeInfo Emp)
{
  using (ISession session = OpenSession())
  {
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Delete(Emp);
    tran.Commit();
   }
  }
}
}

Build the project and make sure that it is error free.

Step 7: Add a new Controller in the Controllers folder, name it as ‘EmployeeInfoController’. Add the following action methods in the controller class:

using MVC4_Using_NHB.Models;
using System.Web.Mvc;
namespace MVC4_Using_NHB.Controllers
{
public class EmployeeInfoController : Controller
{
  EmployeeInfoDAL objDs;
  public EmployeeInfoController()
  {
   objDs = new EmployeeInfoDAL();
  }
  //
  // GET: /EmployeeInfo/
  public ActionResult Index()
  {
   var Employees = objDs.GetEmployees();
   return View(Employees);
  }
//
// GET: /EmployeeInfo/Details/5
public ActionResult Details(int id)
{
  return View();
}
//
// GET: /EmployeeInfo/Create
public ActionResult Create()
{
  var Emp = new EmployeeInfo();
  return View(Emp);
}
//
// POST: /EmployeeInfo/Create
[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
  try
  {
   objDs.CreateEmployee(Emp);
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
//
// GET: /EmployeeInfo/Edit/5
public ActionResult Edit(int id)
{
  var Emp = objDs.GetEmployeeById(id);
  return View(Emp);
}
//
// POST: /EmployeeInfo/Edit/5
[HttpPost]
public ActionResult Edit(int id, EmployeeInfo Emp)
{
  try
  {
   objDs.UpdateEmployee(Emp);
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
//
// GET: /EmployeeInfo/Delete/5
public ActionResult Delete(int id)
{
  var Emp = objDs.GetEmployeeById(id);
  return View(Emp);
}
//
// POST: /EmployeeInfo/Delete/5
[HttpPost]
public ActionResult Delete(int id,FormCollection collection)
{
  try
  {
   var Emp = objDs.GetEmployeeById(id);
   objDs.DeleteEmployee(Emp);  
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
}


Each action method makes a call to the method defined in the EmployeeInfoDAL class. That’s it. Now add views for each action method and test them.

Conclusion

We saw how easy it is to make use of NHibernate in MVC application for building Line of Business (LOB) applications.

 



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in