Showing posts with label ASP.NET MVC 4. Show all posts
Showing posts with label ASP.NET MVC 4. Show all posts

Tuesday, July 15, 2014

FIX: CKEditor not showing up when site is deployed on IIS server (ckeditor-full version 4.4.2)

Scenario:

Recently, I came across an issue due to which CKEditor was not showing up after deploying website in IIS. It was showing an empty placeholder instead. It was showing up completely fine in development environment, and while running site through Visual Studio.

I had "ckeditor-full" (Version 4.4.2)" package added in my MVC project, and also bundles to load "\ckeditor\adapters\jquery.js" and "ckeditor\ckeditor.js" javascript files in the project.

I checked in the code but it all looked fine.

As a resolution, it turned out that, I had to include following line in my view before loading the bundles -

<script type="text/javascript">
    CKEDITOR_BASEPATH = "@Url.Content("~/Scripts/ckeditor/")";
</script>

Hope this will help someone.

Monday, March 31, 2014

Error 403, 403.14, 404 - After deploying ASP.NET MVC website on IIS 7, IIS 7.5

After deploying your ASP.NET MVC website on IIS 7 or IIS 7.5, you might face following errors while browsing your website:

  • 403.14 - Forbidden (The Web server is configured to not list the contents of this directory.)
  • 404 - Not Found (The resource you are looking for has been removed, had its name changed, or is temporarily unavailable)

Following are the possible causes/ fixes for this -
  • Make sure the Application pool targets correct version of .NET framework (i.e .NET Framework v4.0.30319 for .NET 4 and 4.5)
  • Make sure the Pipeline mode of IIS Application pool is "Integrated"
  • Check UrlRoutingModule-4.0 is added in the modules of that website.
  • (To do that, open list of added modules by clicking "Modules" against your website, and see if the module "UrlRoutingModule-4.0" is added or not). If not, then add a module by clicking "Add Managed Module" button, where select System.Web.Routing.UrlRoutingModule as a Module type, and give "UrlRoutingModule-4.0" as its name)
  • Make sure you have following element added in system.webServer section of website's web.config
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules> 
</system.webServer>

In most cases of 403.14, or 404 error, above are the possible causes and fixes. 

Friday, July 5, 2013

When should we not use MVC bundling?

As we all know MVC bundling and minification is a very powerful feature, but recently I faced a strange problem in one of the project as detailed below.

I was using Trent Richardson's Timepicker control to avail time picker functionality in my MVC 4 application. I had relevant JQuery file bundled using MVC bundling feature. I found this working quite well in development environment (Visual Studio 2012).
But when I deployed the website on IIS, I started facing a strange issue, and there was a javascript error "function expected" in that particular bundle. I could see the bundle got loaded because developer tool was showing javascript code when that bundle was selected in "scripts" tab.

Finally, when I referenced the JQuery file directly instead of bundle, it started working fine on IIS. Though the problem got solved, I was than now curious to know what was wrong with that particular file if bundled, and if MVC bundling was actually an issue, then why it was working well in development environment, but not in IIS?

Posting this on various forums gave me following two detailed answers which helped me in identifying in which situations we should avoid using bundling -

Answer 1

Minification is a complex process by making scripts/styles smaller using techniques such variable name shortening, white space elimination, comments removal, etc... It uses ASP.NET Web Optimization that depends on WebGrease for minification. Of course, there can have issues but I personnaly never noticed that.
Here are some situations, where you should not use bundling
  • There is only one file in your bundle. Why bundling ?
  • You are using only famous frameworks such as JQuery or jQuery UI. Do not redistribute scripts that are already served by someone else. Google/Microsoft/Amazon/... already provide CDN for the most popular, open-source JavaScript libraries.
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
  • Your bundle takes only a few Bytes. Web performance Optimization suggests to limit the number of web requests. Everything has a cost. Not very optimal, but sometimes it's better to put inline scripts in your page.
  • In some architectures. Bundles requests contains a unique identifier used for caching. If any file in the bundle changes, the ASP.NET optimization framework will generate a new token, guaranteeing that browser requests for the bundle will get the latest bundle. When working with some architectures, JS updates can be frequent and will invalidate all your bundles.
  • On Dev Environment. It's is really really painful to debug a bundle.
Answer 2

What bundling suppose to do is to put together the script/stylesheet files in a single bundle into a single request and send it to the client so that the browser has to make less calls to get those required script files. In a development environment, when you do debugging in visual studio. It doesn't do the above process unless you specify it to do so. But in a production environment, when the debug is set to false in the web.config file. it will start to do the above process. There can be some other reasons as well. such as the script might have two versions. one for debugging and one for production. I came across such a situation with knockout. in my development environment I had referenced the debug version of the script. But when I put it into the production environment, everything came to a hault. There was a release version for the 
knockout script file and I had to reference that to make everything work again
 
 
Hope this will help you

Saturday, February 2, 2013

FIX: An MVC website configured for Windows Authentication is trying to redirect to Login page while accessing from IIS

I came across a very strange issue recently. My MVC application was configured to use Windows Authentication, and it was deployed on IIS.
While the website was working very properly when accessed from Development environment, means, it was taking the routes into considerations and was properly redirecting the user to specific routes. However, while accessing the website from IIS, it was straight-away redirecting user to a login page. (which obviously was throwing the error, as the windows application is not suppose to have login page).
I checked all configurations on IIS, and also could see only 'Windows Authentication" enabled, which was quite correct.
Though I haven't found any particular reason why it would be happening, however, I learned how to fix this :)
Add following keys in "<appSettings>" section of application's web.config file.


<add key="autoFormsAuthentication" value="false" />
<add key="enableSimpleMembership" value="false"/>


and restart the site on IIS. That should do the magic!
If the issue is too strange, the solution is more than strange...

Hope this saves someone's time and effort :)

Tuesday, November 27, 2012

Investigations: Could not load type 'System.Web.Razor.Parser.[TypeName]' from assembly 'System.Web.Razor, Version=2.0.0.0'

I recently faced this issue while working on my ASP.NET MVC 4 project over .NET Framework 4.5.

System was throwing following error whenever I make a call to any member of RazorEngine.Razor class.
Like Razor.Parse, etc.
In order to investigate the issue, I checked at various places in my project and GAC, and finally I could see following been placed in web.config file of  my project. It seems it is incorrectly creating the binding redirect for System.Web.Razor.


      <dependentAssembly>
        <assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>

Remove this section from web.config file, and the issue should be resolved now.

Friday, May 11, 2012

Implementing Custom Profile in ASP.NET MVC 4 using ProfileBase


This article aims to explain how to work with ProfileProvider in ASP.NET MVC 4, and implementing custom user profile.
As we know, the membership, roles and profile tables have been restructured in MVC 4. Profile information of each user now gets stored in “Profile” table in database.
The below screenshot is taken from an SQL Server database, but you can easily correlate it with other database if your data provider is Oracle, etc. Also, it will work if your profile table is pre-MVC 4 version (i.e. aspnet_Profile).


Each row in this table represents a User profile associated with a User (UserId links User with the profile). 

For each user there is only one row in this table containing complete information about profile.
PropertyNames >> Contains name of each property in profile
PropertyValueStrings >> Text value of each property of corresponding user’s profile. Its stored based on character index. Each profile will have more than one property (as we will see later), and character indexing helps in identifying values corresponding to property.
PropertyValueBinary >> Binary representation of PropertyValueStrings field.

As such, we are least concerned about how the values are stored and retrieved in database, because it’s a job of Profile provider in ASP.NET MVC 4. We do not need to directly deal with this table at all!
Let us have a Walkthrough to understand how to implement this:

If you are not aware about how to enable membership, role and profile providers (System.Web.Providers) in your MVC 4 application, please do visit this link before looking into below walkthrough.

STEP 1 Configure Profile provider in web.config:
Make sure you have following section in <system.web> in your web.config file. Here, “DefaultConnection” is a ConnectionString's name in <ConnectionStrings> section of your web.config. 
Change name, connectionStringName, and applicationName attributes according to your preferences.

<profile defaultProvider="DefaultProfileProvider">

      <providers>
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="MyApp"/>       
      </providers>
</profile>

STEP 2 Define Profile properties:
Define properties that constitutes a user profile in your application. Add them under above added <profiles> section in your web.config. Profile properties can also be grouped, such as Contact, Address, etc.

<properties>
<add name="ForeNames" type="System.String"/>
<add name="LastName" type="System.String"/>
<add name="Gender" type="System.String"/>
<group name="Contact">
<add name="MobileNo" type="System.String"/>
<add name="EmailAddress" type="System.String"/>
</group>
</properties>

That’s all you need to do in web.config.

STEP 3 Add Model for Profile object in your MVC application:
This model represents Profile in your MVC application. Ideally, it should be in sync with the one defined in Web.config.
This model will be used to pass Profile data from Controller action to View, and post them back from View to Controller action.
Add following model in “Models” folder in your MVC structure. (Make a new file, or add it in existing file. It’s all up to you.)
public class ProfileModel
{
[Display(Name = "First Name")]
        public string ForeNames { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Gender")]
        public string Gender { get; set; }

        [Display(Name = "Mobile No")]
        public string MobileNo { get; set; }

        [Display(Name = "Email Address")]
        public string EmailAddress { get; set; }
}

STEP 4 Add a new View, and Bind it with ProfileModel:
Add a new view under “Views” folder (Place it under a controller-specific view folder, or a “Shared” folder, wherever you wish to).
Bind the view with the ProfileModel, and design UI accordingly, and also enforce validations as you wish.
UI should include entry fields for corresponding profile properties, as well as showing validation messages, and a Submit button to the corresponding POST action in controller. (Next steps will show you controller actions).
I am leaving the designing of view to you!

Sample:



STEP 5 Write a GET action to fetch user profile using Profile provider, and launch View created in above step:
A GET action needs to be written in your controller to fetch profile information from database using Profile provider.

public ActionResult EditProfile()
{           
      ProfileBase _userProfile = ProfileBase.Create(HttpContext.User.Identity.Name);
      ProfileModel _profile = new ProfileModel();
      if (_userProfile.LastUpdatedDate > DateTime.MinValue)
      {
          _profile.ForeNames = Convert.ToString(_userProfile.GetPropertyValue("ForeNames"));
          _profile.LastName = Convert.ToString(_userProfile.GetPropertyValue("LastName"));
          _profile.Gender = Convert.ToString(_userProfile.GetPropertyValue("Gender"));
          _profile.MobileNo = Convert.ToString(_userProfile.GetProfileGroup("Contact").GetPropertyValue("MobileNo"));
          _profile.EmailAddress = Convert.ToString(_userProfile.GetProfileGroup("Contact").GetPropertyValue("EmailAddress"));
       }
       return View(_profile);
}

The above controller action is HTTP GET method, and should be called from “Edit Profile” or similar link of your choice in your application. (I have given an example in STEP 7 later)
First of all, it retrieves profile information of specific user (passed as parameter in ProfileBase.Create method) from database.
Also, ProfileModel is instantiated; this is what we are binding with the “Edit Profile” view.
Further, if there exists a user profile for the user, then properties of ProfileModel instance gets assigned according to the actual values in user profile.
Finally, a View is invoked by supplying ProfileModel object for binding.
Note: Here, I assume that your View is named as “EditProfile” and exists in the same controller.
If that’s not the case, you need to set appropriate parameters in a call to “View” method.

STEP 6 Write a POST action to post model to View:
When a user clicks on a Submit button in “Edit Profile” view, an HTTP Post action from a controller gets called. This method accepts a ProfileModel instance updated by user through “Edit Profile” view.

[HttpPost]
public ActionResult EditProfile(ProfileModel model)
{
    if (ModelState.IsValid)
    {
       // Attempt to register the user profile
       System.Web.Profile.ProfileBase profile = System.Web.Profile.ProfileBase.Create(User.Identity.Name, true);

       if (profile != null)
       {
           profile.SetPropertyValue("Gender", model.Gender);
           profile.SetPropertyValue("ForeNames", model.ForeNames);
           profile.SetPropertyValue("LastName", model.LastName);
           profile.GetProfileGroup("Contact").SetPropertyValue("MobileNo", model.MobileNo);
           profile.GetProfileGroup("Contact").SetPropertyValue("EmailAddress", model.EmailAddress);
           profile.Save();
       }
       else
       {
           ModelState.AddModelError("", "Error writing to Profile");
       }
    }     
    return View(model);
}

The above controller action is an HTTP POST method, and gets called when a user clicks a Submit button to Save profile changes.
It first validates, if the user profile changes satisfies all the validations. If not, it will create an instance of ProfileBase object using Reflector for the specific user. It will assign profile properties from the values updated in ProfileModel object. Once done, Save user profile in database. (If the profile for the particular user does not exist, it will create a new one, or else, it will update existing profile).

Step:7 Call to GET action
Finally, we need a user interface to allow user to launch “Edit Profile” view. And for that, we need to call “EditProfile” HTTP GET action (Step 5) of the controller from some UI element.
@Html.ActionLink("Edit Profile", "EditProfile", "Account")

Our example is specific to deal with logged in user’s profile only. But you can easily tweak it by adding a parameter to accept user name to allow users to view/ manage profile of other users’ in your application.