Technical articles on AI agents, Azure, .NET, architecture, and EV charging systems from Sydney.

Category: ASP.NET Page 1 of 5

Category for ASP.NET

Build Custom View Engine to override default views folder in ASP.NET MVC

So here is the situation, I need to build a personalization for the user where they can have different View files based on their user preference or alternatively they can pick their own View folder. To better explain the situation, look at the folder structure below

ViewPersonalisation-FolderStructure

So basically, I don’t want it to be under “Views” folder anymore instead I want my views to be under “Media” folder and by default if the user hasn’t specified which “Views” folder that they want to select then it should use the default one which is “Main” folder

First of all, we need to create our own View Engine that inherits from “RazorViewEngine” and then we need to override the default “ViewLocation“, “PartialViewLocation” and “MasterLocation” with our own default location which is “Media”

Secondly, we need to override “CreateView” method and “CreatePartialView” method to replace the default view location with the one defined in database/user settings

*Note: in the code below “CacheManager.CurrentSite.FolderPath” is storing the “Views” folder that the user has selected in their profile. “UseCustomViewLocation” function is used in this case to not have the personalisation on any of the “Admin Area”
[code language=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;</code>

namespace WebUI.Custom.ViewEngine
{
public class WhitelabelViewEngine : RazorViewEngine
{
private const string WHITELABELVIEWFOLDER = "Whitelabel";
private const string MAINFOLDER = "Main";
private const string EXCLUDED_AREA = "admin";

public WhitelabelViewEngine()
{
base.ViewLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};

base.MasterLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};

base.PartialViewLocationFormats = new[] {
"~/Media/" + MAINFOLDER + "/{1}/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/{1}/{0}.vbhtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.cshtml",
"~/Media/" + MAINFOLDER + "/Shared/{0}.vbhtml"
};
}

protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
IView partialView = base.CreatePartialView(controllerContext, partialPath);

if (UseCustomViewLocation(controllerContext))
{
partialView = base.CreatePartialView(controllerContext, partialPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath));

if (!File.Exists(controllerContext.HttpContext.Server.MapPath(((RazorView)partialView).ViewPath)))
partialView = base.CreatePartialView(controllerContext, partialPath);
}

return partialView;
}

protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
IView pageView = base.CreateView(controllerContext, viewPath, masterPath);

if (UseCustomViewLocation(controllerContext))
{
pageView = base.CreateView(controllerContext, viewPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath),
masterPath.Replace(MAINFOLDER, CacheManager.CurrentSite.FolderPath));

if (!File.Exists(controllerContext.HttpContext.Server.MapPath(((RazorView)pageView).ViewPath)))
pageView = base.CreateView(controllerContext, viewPath, masterPath);
}

return pageView;
}

///
/// to check whether in the custom area or not
///

//////
private bool UseCustomViewLocation(ControllerContext controllerContext)
{
bool useCustomViewLocation = false;

if (controllerContext.RouteData.DataTokens["area"] == null || (controllerContext.RouteData.DataTokens["area"] != null &amp;&amp; controllerContext.RouteData.DataTokens["area"] != EXCLUDED_AREA))
{
useCustomViewLocation = true;
}

return useCustomViewLocation;
}
}
}
[/code]

Lastly, We also need to register our custom view engine in Global.asax
[code language=”csharp”]
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
BootStrapper.Setup();

/*Register Whitelabel View Engine logic*/
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new WhitelabelViewEngine());
}
}
[/code]
 

Custom Authorize Attribute and HTTP 403

In this post, I want to outline in how to create your own Authorize tag and to make sure when you call JSON method with your custom authorize attribute to throw HTTP403 – Forbidden

1. You need to create your own Attribute inherits from AuthorizeAttribute

2. AuthorizeCore is the logic that defines whether you are authorized or not

3. OnAuthorization defines the behaviour when you are not authorized. In this case we want to throw HTTP 403 – forbidden. By doing this in your Javascript, you can catch this 403 error and throw friendly error message to the user

Code Snippet
  1. public class CustomAuthorizeAttribute : AuthorizeAttribute
  2.     {
  3.         protected override bool AuthorizeCore(HttpContextBase httpContext)
  4.         {
  5.             if (httpContext == null) throw new ArgumentNullException(“httpContext”);
  6.             return (SessionData.Member != null && SessionData.Member.MemberId > 0);
  7.         }
  8.         public override void OnAuthorization(AuthorizationContext filterContext)
  9.         {
  10.             base.OnAuthorization(filterContext);
  11.             if (filterContext.Result == null)
  12.             {
  13.                 return;
  14.             }
  15.             else if (filterContext.Result.GetType() == typeof(HttpUnauthorizedResult)
  16.                 && filterContext.HttpContext.Request.IsAjaxRequest())
  17.             {
  18.                 filterContext.Result = new ContentResult();
  19.                 filterContext.HttpContext.Response.StatusCode = 403;
  20.             }
  21.         }
  22.     }

You don’t need to do anything in your controller to implement HTTP403, it is all derived from the custom attribute, you just need to use the attribute and everything will be taken care of. Sample usage

Code Snippet
  1. [CustomAuthorize]
  2.         public ActionResult SaveJobJSON(int jobid)
  3.         {
  4.             string message = string.Empty;
  5.             bool successful = false;
  6.             JobsSavedService JobsSavedService = new JobsSavedService();
  7.             successful = JobsSavedService.SavedJobForMember(jobid, ref message);
  8.             JobsSavedService = null;
  9.             return Json(new { successful = successful, message = message }, JsonRequestBehavior.AllowGet);
  10.         }

Pass Model from Javascript to MVC Controller

Initially, I always pass individual object properties through JSON and form the model in the controller as I wasn’t sure how to pass/form a model from Javascript to controller

Controller

Code Snippet
  1. [AllowAnonymous]
  2.         public ActionResult JsonRegister(string username, string password, string confirmpassword,
  3.                                             string email, string confirmemail)
  4.         {
  5.             MemberModel.RegistrationModel model = new MemberModel.RegistrationModel() {
  6.                                                                                         UserName = username,
  7.                                                                                         Password = password,
  8.                                                                                         ConfirmPassword = confirmpassword,
  9.                                                                                         Email = email,
  10.                                                                                         ConfirmEmail = confirmemail };

Javascript

Code Snippet
  1. $.getJSON(@Url.Action(“JsonRegister”), { UserName: $(“#UserName”).val(),
  2.                                                     Password: $(“#Password”).val(),
  3.                                                     ConfirmPassword: $(“#ConfirmPassword”).val(),
  4.                                                     Email: $(“#Email”).val(),
  5.                                                     ConfirmEmail: $(“#ConfirmEmail”).val()
  6.                                                 }, function (RegisterResult) {
  7.                                                         if (RegisterResult.success) {
  8.                                                             $(‘#RegistrationFields’).hide();
  9.                                                             $(‘#ErrorMessage’).text();
  10.                                                             $(‘#RegistrationMessage’).css(‘display’, );
  11.                                                         }
  12.                                                         else {
  13.                                                             $(‘#ErrorMessage’).css(‘display’, ).text(RegisterResult.errors);
  14.                                                         }
  15.         });

the code above is working just fine but I still feel that there is room for improvement. Below is the code that shows how you can still have your controller accepting the model instead of expanding the properties in the model as the parameters to the controller. The solution is just to have the model being assigned to a variable (in this context called as data) before passing it to the JSON, my previous code was forming the actual object in the JSON code

Controller

Code Snippet
  1. [AllowAnonymous]
  2.         public ActionResult JsonRegister(MemberModel.RegistrationModel model)
  3.         {
  4.             string error = string.Empty;
  5.             if (ModelState.IsValid)

Javascript

Code Snippet
  1. var data = { UserName: $(“#UserName”).val(),
  2.             Password: $(“#Password”).val(),
  3.             ConfirmPassword: $(“#ConfirmPassword”).val(),
  4.             Email: $(“#Email”).val(),
  5.             ConfirmEmail: $(“#ConfirmEmail”).val()
  6.         };
  7.         $.getJSON(@Url.Action(“JsonRegister”), data, function (RegisterResult) {
  8.             if (RegisterResult.success) {
  9.                 $(‘#RegistrationFields’).hide();
  10.                 $(‘#ErrorMessage’).text();
  11.                 $(‘#RegistrationMessage’).css(‘display’, );
  12.             }
  13.             else {
  14.                 $(‘#ErrorMessage’).css(‘display’, ).text(RegisterResult.errors);
  15.             }
  16.         });

ModelState Errors in MVC through JSON

Normally, when you used HttpPost/Form submission to post the view through the controller then you can have the model validation applied automatically through @Html.ValidationSummary()

But how do you get the ModelState errors through Json? You can still use LINQ to get the model errors from the ModelState and pass it through JSON

Code Snippet
  1. public ActionResult JsonRegister(MemberModel.RegistrationModel model)
  2.         {
  3.             string error = string.Empty;
  4.             if (!ModelState.IsValid)
  5.             {
  6.                 IEnumerable<System.Web.Mvc.ModelError> modelerrors = ModelState.SelectMany(x => x.Value.Errors);
  7.                 foreach (var modelerror in modelerrors)
  8.                 {
  9.                     error += modelerror.ErrorMessage + “\n”;
  10.                 }
  11.             }
  12.             return Json(new { success = false, errors = error }, JsonRequestBehavior.AllowGet);
  13.         }

Delayed Script/Waiting in Javascript

I was struggling in finding out of how to make a simple delegate like in AJAX request through javascript. It takes me a few days to figure this out

Basically the problems are:

-I need to execute a piece code of javascript after getting the ticket from web service function

-The webservice function might not be responding to the first request because it waits for the state of the other external component

-The webservice will give the response when the external component is ready

-The client does not know when the external component is ready, neither the web service. But it wil be ready within 1-5 minutes which again depending external component

Possible Solution:

-Using the setTimeOut(function(){acquireTicket();}, 300000) will cause the application to wait for 5 mins before calling the web service , this approach will slowing down the user experience and waste of time because the external component can be ready earlier than 5 mins

-Using the while loop is not good because it makes the browser freezing while waiting and it will wasting the processing power because of the looping

Recommended Solution:

-Recall the function by itself using setTimeout Function using parameter to indicate whether it should go out of the loop or not

-The web service will be checked for every 2 seconds to check the response from the external component. Once the external component is ready then it will move on to execute the next line of code

Access javascript object properties with invalid character

ParseJSON returning you an object from your AJAX Call, the problem that I have is my object properties has invalid character (e.g “#”)

Assuming jsonData is my variable that contains the following information

I’d like to grab the property of “#innerxml”

Normally I can do this to get the property of an object but in this case I can’t due to invalid character

(jQuery.parseJSON(jsonData)[0]).#innerxml

So How do I access an object which has properties where one of the property name is using an invalid character (e.g “#”)

I can access with the following style

(jQuery.parseJSON(jsonData)[0])[‘#innerxml’]

Simple Collapsible Panel using JQuery

I found a simple collapsible panel developed by a guy called Darren Ingram and I’d definitely recommend it to anyone wanted to implement collapsible panel. His Jquery implementation of collapsible panel is very simple. It just need 2 files (diQuery-collapsiblePanel.js and diQuery-collapsiblePanel.css – where the css classes can even be integrated to your own css class). I prefer this implementation because it’s just a div implementation and the JQuery script will be hooked up to the div elements (where the class name is collapsibleContainer) upon the page loaded. Simple and lightweight in comparison to the collapsible panel of AJAX toolkit (http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/CollapsiblePanel/CollapsiblePanel.aspx)

the source code for the collapsible panel by Darren Ingram can be downloaded from his website (http://www.darreningram.net/pages/examples/jQuery/CollapsiblePanelPlugin.aspx)

Enter button in TextBox ASP.NET

This article is demonstrating how to wire up an enter key into a textbox. For example you have a search text box where you press enter then it will click go button and at the same page you have another textbox where you want to do another button click when you press the enter which means it’ is not necessary to post the page. This java script is used to capture the key event of enter and execute the LinkButton and ASP.NET button Click Event on the server side. Please add this javascript to your javascript common library or add this to your master page. This piece of code works in Firefox as well


function ButtonKeyPress(evt, thisElementName)
{
    if(evt.which || evt.keyCode)
    {
        if ((evt.which == 13) || (evt.keyCode == 13))
        {
            // alert('post back href: ' +document.getElementById(thisElementName).href);

            if (typeof document.getElementById(thisElementName).href != 'undefined')
            {
                location = document.getElementById(thisElementName).href;
            }
            else
            {
                document.getElementById(thisElementName).click();
            }
            return false;
        }
    }
    else
    {
        return true;
    }
}

And add this to your .NET code behind on the page load

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
         If Not Page.IsPostBack Then


            If (User.Identity.IsAuthenticated) Then
                Response.Redirect("frmTimeMain.aspx")
            End If

            txtGUID.Attributes.Add("onkeydown", "ButtonKeyPress(event, '" + lnkSubmit.ClientID + "')")
            txtPassword.Attributes.Add("onkeydown", "ButtonKeyPress(event, '" + lnkSubmit.ClientID + "')")
          End If
    End Sub

ASP.NET Calendar selected day on click method

I’ve a case where I have an ASP.NET calendar that has a page load method that automatically select a date when it’s loaded. I also have an event defined for Selected_Changed which will be triggered only when the user select any other date other than pre-selected date on the load

Private Sub ctlCalendar_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ctlCalendar.SelectionChanged
        If (Not String.IsNullOrEmpty(CalendarPreviousPage)) Then
            BaseCalendar.SelectedDate = ctlCalendar.SelectedDate
            Response.Redirect(CalendarPreviousPage)
        End If
    End Sub

But how do I wire up an event or when the selecteddate being clicked?You can use DayRender event and attach it to a javascript in this case I want to go back to previous page. BaseCalendar.Selected date can be any date where you want to set up/wire up the logic

 Private Sub ctlCalendar_DayRender(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DayRenderEventArgs) Handles ctlCalendar.DayRender
        Dim d As CalendarDay
        Dim c As TableCell
        d = e.Day
        c = e.Cell

        If (BaseCalendar.SelectedDate.Value = d.Date) Then
            c.Attributes.Add("OnClick", "history.go(-1)")
        End If

    End Sub

Reflection GetProperty case sensitive issue

Reflection on .NET by default is case sensitive for the class member. To make it case insensitive you need to pass BindingFlags.IgnoreCase . I’ve passed the ignorecase flag and now it doesn’t return anything!!!


 Dim pi As PropertyInfo = Me.[GetType]().GetProperty(fieldname, BindingFlags.IgnoreCase)

Basically, if you pass one flag then the other flags will be overwritten by default which means all the default flags are disappeared. So to make it case insensitive then you need to pass other binding flags


 Dim pi As PropertyInfo = Me.[GetType]().GetProperty(fieldname, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance)

Page 1 of 5

Powered by WordPress & Theme by Anders Norén