I have a Master page for my site that is used for styling the rest of the site and doing user authentication. This works fine except that I have one page that I would like to retain the styling from the master but not do the authentication since this is the page that tells the user that they aren't authenticated. How could I override the MasterPage's Page_Load method from this one page? Any other thoughts on how I could not authenticate on this one page without moving authentication from the master?
R – ASP.NET Master page Page_Load Override
asp.netmaster-pages
Related Solutions
Website:
The Web Site project is compiled on the fly. You end up with a lot more DLL files, which can be a pain. It also gives problems when you have pages or controls in one directory that need to reference pages and controls in another directory since the other directory may not be compiled into the code yet. Another problem can be in publishing.
If Visual Studio isn't told to re-use the same names constantly, it will come up with new names for the DLL files generated by pages all the time. That can lead to having several close copies of DLL files containing the same class name, which will generate plenty of errors. The Web Site project was introduced with Visual Studio 2005, but it has turned out not to be popular.
Web Application:
The Web Application Project was created as an add-in and now exists as part of SP 1 for Visual Studio 2005. The main differences are the Web Application Project was designed to work similarly to the Web projects that shipped with Visual Studio 2003. It will compile the application into a single DLL file at build time. To update the project, it must be recompiled and the DLL file published for changes to occur.
Another nice feature of the Web Application project is it's much easier to exclude files from the project view. In the Web Site project, each file that you exclude is renamed with an excluded keyword in the filename. In the Web Application Project, the project just keeps track of which files to include/exclude from the project view without renaming them, making things much tidier.
The article ASP.NET 2.0 - Web Site vs Web Application project also gives reasons on why to use one and not the other. Here is an excerpt of it:
- You need to migrate large Visual Studio .NET 2003 applications to VS 2005? use the Web Application project.
- You want to open and edit any directory as a Web project without creating a project file? use Web Site project.
- You need to add pre-build and post-build steps during compilation? use Web Application project.
- You need to build a Web application using multiple Web projects? use the Web Application project.
- You want to generate one assembly for each page? use the Web Site project.
- You prefer dynamic compilation and working on pages without building entire site on each page view? use Web Site project.
- You prefer single-page code model to code-behind model? use Web Site project.
Web Application Projects versus Web Site Projects (MSDN) explains the differences between the web site and web application projects. Also, it discusses the configuration to be made in Visual Studio.
Here's how I do it.
I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.
Create the interface
interface ICustomPrincipal : IPrincipal { int Id { get; set; } string FirstName { get; set; } string LastName { get; set; } }
CustomPrincipal
public class CustomPrincipal : ICustomPrincipal { public IIdentity Identity { get; private set; } public bool IsInRole(string role) { return false; } public CustomPrincipal(string email) { this.Identity = new GenericIdentity(email); } public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.
public class CustomPrincipalSerializeModel { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } }
LogIn method - setting up a cookie with custom information
if (Membership.ValidateUser(viewModel.Email, viewModel.Password)) { var user = userRepository.Users.Where(u => u.Email == viewModel.Email).First(); CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel(); serializeModel.Id = user.Id; serializeModel.FirstName = user.FirstName; serializeModel.LastName = user.LastName; JavaScriptSerializer serializer = new JavaScriptSerializer(); string userData = serializer.Serialize(serializeModel); FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket( 1, viewModel.Email, DateTime.Now, DateTime.Now.AddMinutes(15), false, userData); string encTicket = FormsAuthentication.Encrypt(authTicket); HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket); Response.Cookies.Add(faCookie); return RedirectToAction("Index", "Home"); }
Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest
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(); CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData); CustomPrincipal newUser = new CustomPrincipal(authTicket.Name); newUser.Id = serializeModel.Id; newUser.FirstName = serializeModel.FirstName; newUser.LastName = serializeModel.LastName; HttpContext.Current.User = newUser; } }
Access in Razor views
@((User as CustomPrincipal).Id) @((User as CustomPrincipal).FirstName) @((User as CustomPrincipal).LastName)
and in code:
(User as CustomPrincipal).Id
(User as CustomPrincipal).FirstName
(User as CustomPrincipal).LastName
I think the code is self-explanatory. If it isn't, let me know.
Additionally to make the access even easier you can create a base controller and override the returned User object (HttpContext.User):
public class BaseController : Controller
{
protected virtual new CustomPrincipal User
{
get { return HttpContext.User as CustomPrincipal; }
}
}
and then, for each controller:
public class AccountController : BaseController
{
// ...
}
which will allow you to access custom fields in code like this:
User.Id
User.FirstName
User.LastName
But this will not work inside views. For that you would need to create a custom WebViewPage implementation:
public abstract class BaseViewPage : WebViewPage
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new CustomPrincipal User
{
get { return base.User as CustomPrincipal; }
}
}
Make it a default page type in Views/web.config:
<pages pageBaseType="Your.Namespace.BaseViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
and in views, you can access it like this:
@User.FirstName
@User.LastName
Best Answer
Maybe check in your master page somewhere in Request.Current.Url for the current page name (Whatever.aspx) and skip authentication for it.