Category: ASP.NET MVC

Five common mistakes for ASP.NET MVC accesing resources : css, js, images, ajax

This is a Razor /MVC5 variant of older post
http://msprogrammer.serviciipeweb.ro/2010/10/09/five-common-mistakes-for-asp-net-mvc-accesing-resources-css-js-images-ajax/

To have once for all the link to show to people, because too much makes the same error again and again. (From here – you can use ResolveUrl or Url.Content – it’s the same for me. I use ResolveUrl because I used first …)

Case 1 The image does not display

Please check you have the following :

 <img src="@Url.Content("~/Content/images/YOURIMAGE.jpg" )" alt="image" style="border:0" /> or 
 
<img src="~/Content/images/YOURIMAGE.jpg" alt="image" style="border:0" /> 

Case 2 The css does not show

Please check you have the following :

 @string.Format("<link href="{0}" type="text/css" rel="stylesheet" />", Url.Content("~/Content/your.css"))  

or

 <style type="text/css">
@import '@Url.Content("~/Content/your.css")';

</style>  
  <style type="text/css">
<link href='~/Content/your.css' type='text/css' rel='stylesheet' />

</style>  

Case 3 The js does not execute (undefined error)

3.1 Please check you have the following :

 <script type="text/javascript" src="@Url.Content("~/Scripts/yourjs.js")"></script> 

or

 <script type="text/javascript" src="~/Scripts/yourjs.js"></script> 

This should be either in _Layout.cshtml, or in the scripts section

 @section scripts {   } 

in your .cshtml file.
3.2 please check in browser console ( press F12 ) for any javascript error that code may have

Case 4 The js does execute in .cshtml page, but did not execute under js file

Please check you DO NOT have the following @something in the js file. The js file is not interpreted by the same engine as cshtml, so can not interpret asp.net tags. Instead , add a parameter to your function for each @ variable that you have. Simple example : Let’s say in cshtml you have :

 <script type=”text/javascript”>

function Generate(){

window.open('@Url.Action(“About”)’);
}

</script> 

and you call Generate() from .cshtml file. Now you want the same in a .js file. The function Generate will have a parameter instead of Razor variable

 function Generate(url){  window.open(url); } 

and call like this from .cshtml file:

 Generate('@Url.Action("About")'); 

Case 5 The ajax request gives you a 404 error.

Please ensure that you have

 @Url.Content("~/path”) 

and not

 /path 

when you call the Ajax URL

Bonus 1: T4MVC , http://mvccontrib.codeplex.com/releases

Bonus 2: Edit the project file and put <MvcBuildViews>true</MvcBuildViews>

( short url: http://bit.ly/asp5Mistakes)

MVC Export List of objects to Excel-Word-PDF-CSV-HTML-XML–Razor style

This is the second part of the demo of the Exporter  in action  – this time in MVC .

It is a little more complicated, because you need to show to the exporter the full path where to put the generated file

string filePathExport = Server.MapPath(“~/exports/a” + ExportBase.GetFileExtension((ExportToFormat)id));

All others are the same easy stuff  -add Nuget package and export in 3 lines – and all action code is 6 lines long:

            List<Electronics> list = Electronics.GetData();
            ExportList<Electronics> exp = new ExportList<Electronics>();
            exp.PathTemplateFolder = Server.MapPath("~/ExportTemplates/electronics");
            string filePathExport = Server.MapPath("~/exports/a" + ExportBase.GetFileExtension((ExportToFormat)id));
            exp.ExportTo(list, (ExportToFormat)id, filePathExport);
            return this.File(filePathExport, "application/octet-stream", System.IO.Path.GetFileName(filePathExport));

 

 

 

 

GitHub Demo at https://github.com/ignatandrei/Export_Word_Excel_PDF_CSV_HTML

The Nuget package is at http://www.nuget.org/packages/Exporter/

YouTube demo at http://youtu.be/DHNRV9hzG_Y

SameId – skip

In the previous post I have show how two users can see each other if they are editing the same product ( in my example , product id 5)

But not in all cases the users should be notified about each other – like in , let’s say, view product Id 5.

In this case we have an attribute to apply to the action [SameIdSkip]

A video will show you :

Same object edited by 2 users–proactively notifying users

This is a practical example about how two users that comes on the same page will be notified one about other( after an idea of Adrian Petcu) . See the picture :

image

With the NuGet package you can install in your application in this steps:

To run :
1. install package from Nuget
2. in Filter.Config add following line:  filters.Add(new SameIdAlert.SameIdFilter());
3. In Route.Config, after
routes.MapHubs();
GlobalHost.DependencyResolver.Register(typeof(IAssemblyLocator) ,() => new SameIdAlert.SameIdAssemblyLocator());
4. In the View that you want the user to be notified add the following lines in the @section scripts{
<!–Script references. –>
<!–The jQuery library is required and is referenced by default in _Layout.cshtml. –>
<!–Reference the SignalR library. –>
<script src=”~/Scripts/jquery.signalR-1.1.3.js”></script>  <!–or whatever signalr library version you have –>
<!–Reference the autogenerated SignalR hub script. –>
<script src=”~/signalr/hubs”></script>
<!–SignalR script to update the chat page and send messages.–>

and somewhere:

@{Html.RenderPartial(“SameId”);}

5. In _Layout  move jquery declaration
@Scripts.Render(“~/bundles/jquery”)

before RenderBody

6. If you decide to put into _Layout and you want to skip an action, please put  [SameIdSkipAttribute] to the action

7. If you want more action parameters than the default id , just put
[SameIdAttribute(“parameter name 1″,”parameter name2”)
to the action
8. If you decide that you want just several actions then modify
filters.Add(new SameIdAlert.SameIdFilter(false));
and put
[SameIdAttribute]
View online at http://SameId.apphb.com

Source code at https://github.com/ignatandrei/SameId

NuGet package at https://www.nuget.org/packages/sameid

Video demo at http://youtu.be/wjkoMs98Z8U

If you want to help me, see the issues that can be solved here:https://github.com/ignatandrei/SameId/issues

MVC Help View Razor

My passion for .tt files is great . T4MVC is the best example of what you can achieve with .tt files in MVC . 

Now, the problem: For each project you have a help file must be created. I mostly work with ASP.NET MVC projects – so I frequently have this problem.

I have then created a .tt file that generates summary help .cshtml Razor files for each View that you have in an ASP.NET MVC project.  This .t t file generates for you the folder structure (including Areas ) for having a view help file for each view that you have in the project.
More, if the help file already exists in the project, it will be not overwritten.

The template can be customized:
-the folder name:
//change here the location folder where the help files will be generated
static string HelperFolderName="Help";
-the content of the file
//change here the default content of the file
string TextFile = "<html><body>This is the help file for the view {0}</body></html>";

(For improvements please create an issue on github)
See demo at http://youtu.be/ZGsNHyFA9yw
You can download from https://github.com/ignatandrei/RazorHelpFile/ 

Use the help file with

<a href=’@Url.Content("~/Help/Views/Home/Index.cshtml")’ target="_blank">Index Help</a>

Enjoy!

MVC , JsonResult , DateTime and TimeZone

The jsonresult of date time is serializing to the string /Date and some integer value starting with 1970 . The problem is that the browser interprets this value accordingly to the LOCAL TimeZone – and thus the same date is going to be interpreted with a difference.

I was thinking that I can adjust from UTC time offset of the server( obtained with .NET from TimeZoneInfo.Local.BaseUtcOffset.TotalMinutes) and the UTC time offset of the client( obtained with (new Date()).getTimezoneOffset() + UTCServerMinutes; ). Unfortunately, the code does not work for SAMOA ( 13 hours difference).

Pay attention that the server is sending SAME data – just the browser is interpreting from the local user time zone.

So the solution is to convert the  date to a string ( I have chosed yyyy-MM-ddTHH:mm:ss) and interpret in javascript( see date2 below).

The server code – I have put my birthdate 16 april 1970

DateTime res = new DateTime(1970, 04, 16, 22, 0, 0);
[HttpPost]
        public JsonResult GetDateBirth()
        {

            var str = res.ToString("s");
            return Json(new { date =res, datestring=str, ok = true });

        }

The Javascript code:

function GetJsonDate() {
        $.ajax({
            type: "POST",
            url: '@Url.Action("GetDateBirth")',
            datatype: "JSON",
            contentType: "application/json; charset=utf-8",
            success: function (returndata) {
                if (returndata.ok) {
                    window.alert('The server is sending:' + returndata.date + " -- " + returndata.datestring);
                    var d = parseInt(returndata.date.substr(6));
                    var date1 = new Date(d);
                    var date2 = dateFromSortable(returndata.datestring);
                    var date3= getDateString(returndata.date);
                    window.alert('original: ' + date1  + '\r\n'  + ' iso correct:'+ date2 + '\r\n'+ ' utc difference not good:' + date3);

                }
                else {
                    //this is an error from the server
                    window.alert(' error : ' + returndata.message);
                }

            }
        }
        );
    }
    function dateFromSortable(dateStr) {
        var parts = dateStr.match(/\d+/g);
        return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);
    }
    
    function getDateString(jsonDate) {
        //does not work correctly for SAMOA - it have some hours difference
        var UTCServerMinutes = @serverMinutes;
        if (jsonDate == undefined) {
            return "";
        }
        var utcTime = parseInt(jsonDate.substr(6));

        var dateUtc = new Date(utcTime);

        var minutesOffset = (new Date()).getTimezoneOffset() + UTCServerMinutes;

        var milliseconds = minutesOffset * 60000;
        var d = new Date(dateUtc.getTime() + milliseconds)
        return d;
    }

How to test it:

Run the project. Click “Get Json Date” – and you will see the three dates equal.

image

Now change the time zone to Samoa ( or other, if you live in Samoa Winking smile)

image

Click again on “Get Json Date”  – the date will  same 16 april 1970 just for the date2  – obtained from dateFromSortable javascript function.

image

Please note that the local time zone is NOT affecting the values transmitted via ViewBag/ViewData/Model, but just the ones transmitted via Json.

The project can be downloaded from here

MVC and auto persisting values

When you have a textbox in HTML (let’s say

<input name=”FirstName” type=”text” />

)
And it binds to “FirstName” Property of a Model, and in HttpPost Action you do modify the value and return the same view, the value shown in the textbox is the posted one, not the modified one. ( The first thought is that HttpPost is not executing – but it is a false impression!)
The solution is:
ModelState.Remove(“FirstName”)

or, better

http://lennybacon.com/2010/09/07/RemovingPropertiesFromTheModelStateTheTypedWay

(and it’s not a bug, it’s a feature: classical example: numeric textbox/ numeric property and user enters “aaa” – the validation error appears and the textbox must have aaa, not 0 or default value for the property )

Redirect and Ajax Redirect in MVC

In the sample example I will have various methods to perform redirects from main page to “About” page of a simple MVC site. In my opinion, there are only 3 cases – 2 goods and one bad – to perform redirection with or without Ajax.

 

First case:  A sample redirect and a sample link:

The action is

 public ActionResult RedirectToAboutNoAjax()
        {
            return RedirectToAction("About");
        }

and in the View I call in a simple <a href, generated by :

@Html.ActionLink("Redirect no ajax to about", "RedirectToAboutNoAjax", "Home")

When you click the link, the following happens : a 302 Found answer is send to the browser with the new Location. The browser goes to the page requested.
image
  

Second case( not good ajax): Call same action from ajax – in hope that ajax will do the redirect alone, without coding further.Modified only the code that calls the action, transforming to ajax.

<a href="javascript:AjaxNotGoodForRedirect('@Url.Action("RedirectToAboutNoAjax", "Home")')">Redirect not good with ajax - returns the page</a>

 What it happens is the same: the ajax code calls the RedirectToAboutNoAjax , that redirects to about – and the result is the page. It is no redirect performed to the page itself – rather, on the ajax itself!And , to proof it, I will show the message of html returned in an message:image

Third case( good with ajax): Call a action that returns the new url as a json data parameter and make javascript know that.The action:

 [HttpPost]
        public ActionResult RedirectToAboutWithAjax()
        {
            try
            {
                
                //in a real world, here will be multiple database calls - or others
                return Json(new { ok = true, newurl = Url.Action("About") });
            }
            catch (Exception ex)
            {
                //TODO: log
                return Json(new { ok = false, message = ex.Message });
            }
        }

The javascript:

function AjaxGoodRedirect(urlAction) {
        $.ajax({
            type: "POST", // see http://haacked.com/archive/2009/06/24/json-hijacking.aspx
            url: urlAction,
            data: {}, //to send data see more at http://bit.ly/mvc_ajax_jquery
            datatype: "JSON",
            contentType: "application/json; charset=utf-8",
            success: function (returndata) {
                if (returndata.ok)
                    window.location = returndata.newurl;
                else
                    window.alert(returndata.message);

            }
        }
        );
    }

Note: You can combine the returning the RedirectToAction with Json by checking Request.IsAjaxRequest value and returning either FirstCase, either ThirdCase.

You can find the example for download here
If you want more details, please comment – and I will provide any further explanations.