Sunday, July 26, 2015

C# MetadataException: Unable to load the specified metadata resource error

This post will be about how to fix the "MetadataException: Unable to load the specified metadata resource" error in your ASP.NET web MVC and other applications. I'll keep this one short - what is going on is that the connection string that you used to setup the edmx for the entity model is different from the one now in your Web.Config file. How does it happen and what to do about it? Please see the below points -

  • Check to see if you recently changed connection strings for production deployment. This is actually the most common reason behind this problem.
  • Check the entity names for csdl, ssdl and msl in the connection string in the Web.Config file. These appear right after the "metadata=res://*/" part of the connection string in the Web.Config file.
  • One thing to keep in mind (that also follows from the above points) is that the actual database name and connection infromation is most likely correct. I'm saying this because when we think of connection strings, we tend to check only the database name and connection information. In this case it's the stuff that comes before the actual connection info (that is, before the "provider..." part of the string) that is likely to be messed up.
  • Sometimes we copy paste the conenction strings between different applications. This is fine but remember that if you do it, then you must change the names of the csdl, ssdl and msl as well in addition to key and the actual connection info. Copying pasting connection strings between applications is another thing that usually causes this problem.


So bottomline, if you encounter the "MetadataException: Unable to load the specified metadata resource" error, then check each and every letter in your connection string and ensure that the parts at the beginning (the ones between "metadata=//*/" and "provider") match with what was used to create the edmx entity model initially.

Friday, July 24, 2015

ASP.NET MVC Renders Length=4 in Html.ActionLink

You might have noticed this really strange behavior in ASP.NET MVC4 (and possibly other versions too) where @Html.ActionLink inexplicably appends the rendered links with "?Length=4". For example,

@Html.ActionLink("My App Header", "Index", "Home", new { //your html attributes })

becomes

<a href="/MyApp/?Length=4">My App Header</a>

This seems to make no sense at all, but there indeed is an explanation but before we get to that, let's first see a few ways of fixing it.

Solution 1 - Just add a null paramter after the Controller name parameter. Sp, change

@Html.ActionLink("My App Header", "Index", "Home", new { //your html attributes }) to

@Html.ActionLink("My App Header", "Index", "Home", null, new { //your html attributes })

Solution 2 - Use @Url.Action instead. So, basically change

@Html.ActionLink("My App Header", "Index", "Home", new { //your html attributes }) to

<a href="@Url.Action("Index", "Home")" //your html attributes>My App Header</a>

So, now with the solutions out of the way, here is the explanation for just where the Length=4 thing comes from - Basically the @Html.ActionLink method that your code runs in these cases is defined as follows -

public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, object htmlAttributes)

So, when ASP.NET MVC engine comes across a call like @Html.ActionLink("My App Header", "Index", "Home", new { //your html attributes }), it takes "Home" as the routeValues parameter instead! The way routValues parameter works is that it looks for all public properties in the passed object and uses them for routing as per the routing configuratin. In the case of "Home" object, which is a string, the only public property is "Length" Now, since usually you don't have a "Length" route property in your configuration, it just appends the property name and value to querystring instead. Yes, the ASP.NET MVC Convention over Configuration at work here!! This is actually kinda cool when you think about it!! Now, as for why adding null in @Html.Action fixes it, it's because the null object doesn't have a public property (duh!). As a fun experiment, you could try adding another paramter to @Url.Action and you'll find the Length=4 querystring parameter in your rendered links again!

ASP.NET MVC Upload Large Files

I recently had to setup a website that required uploading huge files ranging from a few MBs to a few GBs. If you have come across this problem, you'll see that the control never reaches the Controller (pun not intended!) when uploading anything over 304 MB. Turns out ASP.NET requires the Web.Config file to be updated with the following -

  1. maxRequestLength attribute - This attribute tells ASP.NET engine the maximum length of the request (duh!). This goes in the httpRuntime tag of your system.web file. The httpRuntime tag should already be present in your Web.Config, so just look it up and add the maxRequestLength attribute in there. For example -
    <system.web> <httpRuntime targetFramework="4.5" maxRequestLength="2147483647"/> </system.web>
    It is set in KB and is set to 4096KB. .
  2. maxAllowedContentLength attribute - This attribute tells ASP.NET engine the maximum content length (again duh!). This also goes in the Web.Config file, but in the requestLimits tag under requestFiltering under security tags in system.webServer. This might not be already present in your Web.Config file so just copy paste the below underlined code under the system.webServer tag -

    <system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="2147483647" /> </requestFiltering> </security> </system.webServer>
    It is set in Bytes. .

And that's it. Now you can upload those huge files without any problems. A few things to note -
  1. The number in the maxRequestLength attribute is in KB (KiloBytes) but the number in the maxAllowedContentLength attribute is in Bytes.
  2. In cases when the sizes mentioned in maxRequestLength and maxAllowedContentLength attrbutes differ, ASP.NET engine will use the smaller one.
  3. The sizes are in unsigned integers, so they do have an upper limit.
  4. This is probably off topic but remember to not use functions like "ReadToEnd()" for reading files.

Thursday, July 2, 2015

ASP.NET MVC Form Submitting Twice Error

In this post I want to present the causes and resolutions of the cases when a form in a web application automatically submits more than once (usually twice). This usually happens with the forms created with @using (Ajax.BeginForm()) approach. A developer new to ASP.NET MVC can spend hours trying to find out the lines in their code that are duplicated resulting in duplicate form submissions. I have been there as well.

So, what causes this error? It happens because jquery.unobtrusive-ajax.js file is referenced more than once in the webpage. This could be as simple as the script tags being accidentally copied-pasted more than once in the page header or as complicated as a result of some idiosyncrasies of ASP.NET MVC Bundling features. Here are a few things that you can do to help locate and fix duplication.

  1. Turn of Bundling optimizations - The first thing to debug it is to set BundleTable.EnableOptimizations = false in the RegisterBundles method of your BundleConfig.cs file in the App_Start folder. This will ensure that the individual script tags for all of the scripts are visible.
  2. Remove the wildcards in ScriptBundle().Include() - Visual Studio usually creates some of the jQuery references using * wildcards. This can be found in the RegisterBundles method in the BundleConfig.cs file. Specifically, you're looking for the following line -
    bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/jquery.unobtrusive*"));
    Here jquery.unobtrusive* allows all of the unobtrusive files to be included in the project. But sometimes, if your script folder has both the regular (jquery.unobtrusive-ajax.js) and the minified (jquery.unobtrusive-ajax.min.js) versions of the file, essentially including the same file twice. Once you have isolated this as the cause, you can consider removing non-minified from the production server.
  3. Check if any other views have the same Script.Render lines - Sometimes, visual studio will include the script sections in views by default for ASP.NET MVC projects, which can result in the developer accidentally copying the @Scripts.Render("~/bundles/jqueryval") line in more than one views. So, do a global search for the @Scripts.Render("~/bundles/jqueryval") line and remove it at all places except for the _Layout.cshtml / master page.
  4. Check to ensure that jquery.unobtrusive-ajax.js file is included only once in the ScriptBundle - For this, you can do a seach for jquery-unobtrusive in the BundleConfig.cs file. If the same file or its minified versions appear more than once, then remove them.
  5. Turn off bundling and include the script tags in your page - If nothing else works, you can consider turning off the bundling. You can do this by removing the @Scripts.Render("~/bundles/jqueryval") line from your layout and all other views. Then add the script tags manually to only your layout or master page. This will help rule out the bundling issues. This will most likely fix this problem for good, as much as I like the bundling approach (Note: At the risk of being super cliche`, I should mention that it's not the bundling at fault here, it's how it's used in the application).

Wednesday, July 1, 2015

How to fix "$ is not a function", "$ or jQuery are not defined" errors

In this post, I'll be explaining time tested remedies for the below erros commonly seen in ASP.NET MVC applications -

SyntaxError: missing } in compound statement

ReferenceError: jQuery is not defined

ReferenceError: $ is not defined

TypeError: $ is not a function

You're likely to see these errors when deploying a new application or if you have made modifications to the BundleConfig.cs, _Layout.cshtml, master pages or other such files. I realize that the files that I listed are ASP.NET MVC specific, but the resolutions that I will be listing below apply to most technologies out there. BundleConfig.cs and _Layout.cshtml just refer to the places in ASP.NET MVC where we usually tell the ASP.NET MVC application where the scripts and styles are reside.

So, the error message "jQuery is not defined" clearly tells us that the jQuery script reference is missing. But when you you look in your scripts folder, it's there. The other errors don't even explain what could be wrong, but fear not, try out the below decetively simple resolutions and your errors should go away in a jiffy -

  1. Check to ensure that the jquery file with the proper version is indeed present in your Scripts (or wherever you store the script files) folder - The jquery version part seems to cause these issues quite a bit, so ensure that the version referenced in your view/webpage is exactly the same as the version in the name of the file. In ASP.NET MVC world, you have the option to replace the version number with {version}, that is very helpful in avoiding this problem. So, your BundleConfig.cs will look like
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));
  2. Ensure that the script reference to your jquery file is indeed there in the rendered HTML page - This goes without saying but in an ASP.NET MVC application, sometimes the scripts will be bundled based on the setting of BundleTable.EnableOptimizations, which makes it almost impossible to see which scripts are actually referenced. Try setting BundleTable.EnableOptimizations to false to be able to see the script tags in the rendered page. I'll go further into the details of how to do it and where in the next item.
  3. Check whether Bundle optimizations are on or off - Another commonly overlooked issue results from the default settings of the optimizations. Basically, ASP.NET MVC allows us to pick the minified versions and regular versions of script files based on this configuration setting. If you're not familiar with it, look for BundleTable.EnableOptimizations in the RegisterBundles method of your BundleConfig.cs file. If you see something like
    BundleTable.EnableOptimizations = true;
    then the application will be looking for the minified version of the scripts regardless of the name of the file in your BundleCollection. For example, if your jquery file is called, jquery-3.0.1.js and your BundleCollection line says ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js")); and BundleTable.EnableOptimizations is set to true, then the app will be looking for jquery-3.0.1.min.js and not the jquery-3.0.1.js file. The solution here is to just uploading the minified jquery-3.0.1.min.js file. If you don't have the minified file, then you could set the BundleTable.EnableOptimizations to false and that would remedy it. A side benefit of setting the BundleTable.EnableOptimizations to false for testing is that then you'd be able to see the script tags on the rendered HTML page for each of your scripts, as I mentioned in a previous point. On a side note, you'd also want to check whether your Web.Config is set to debug or release mode.
  4. Ensure that the jquery script reference occurs before any other script references in the webapge/view - This is another common problem when some other scripts that need jquery appear in your script reference section before the jquery file reference. These scripts look for jquery but the jquery file is not loaded because it's referenced further down the line. Just put the jquery reference on the top of your scripts section and you should be good.
  5. Ensure that the jquery reference occurs before other references inside the BundleConfig.cs - The scripts added to the ASP.NET MVC ScriptsBundle render in the same order in which they appear in the BundleConfig.cs file. The remedy is simple, just put the ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js")); line at the top of your RegisterBundles method.
  6. Check the file sizes of the jquery file on your deployment server - This one almost sounds silly but I've seen cases when the file is not properly uploaded during deployment because of FTP errors etc. The way normal FTP works, if something breaks down during the STOR request in the middle of a big upload, at times the files being uploaded will stay on the server even though they were not fully uploaded. In other words, your file gets partially uploaded (or just an empty file is uploaded) when the upload request fails and now a cursory look will reveal that the file is there...but well, not really. If you don't have access to the production server, then it'd help to look at the logs for any errors during uploads (yes, many of the FTP clients are set to keep going in case of errors).
  7. Check the chaching mechanism of your app - Sometimes the app will cache bad files or sections of pages etc and no matter how many times you refresh, the problem won't go away. One less than ideal solution that I use is deleting the BundleCollection contents completely. You can do this by adding the following lines to the top of your RegisterBundles method in the BundleConfig.cs file (you wouldn't want to do it in the production code though) -
    bundles.Clear(); bundles.ResetAll();


So, basically to summarize, we want to ensure that the name of the your jquery file matches exactly with the file name that shows up in the script tag in your view, masterpage, _layout.cshtml etc...and the size of the file matches and that the jquery reference script tag appears before all other scripts that you might be including. That's about it. In ASP.NET MVC world, there could be further complications because of the BundleConfig or WebConfig settings, but they're also easy to get around by a few small changes.