Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

April 2011 - Posts

Dumping DataTable to debug window
 

Here’s one little method I use to write out debug information when investigating some new (legacy but new to me) system. Usually I remove this method later when I know how code works. It’s maybe not the best way to debug things but it works like charm in many situations.


public void DumpDataTable(DataTable table)

{

    foreach (DataRow row in table.Rows)

    {

        Debug.Print("------------------------------------------");

 

        foreach (DataColumn col in results.Columns)

        {

            Debug.Write(col.ColumnName);

            Debug.Write("=");

            Debug.WriteLine(row[col.ColumnName]);

        }

    }

}


Hope it helps somebody :)

Posted: Apr 29 2011, 06:36 PM by DigiMortal | with no comments
Filed under:
Creating tag cloud using ASP.NET MVC and Entity Framework
 

I am building events site on ASP.NET MVC 3 and Entity Framework. Today I added tagging support to my site and created simple tag cloud. In this posting I will show you how my tag cloud is implemented. Feel free to use my code if you like it.

EF model: Event and tags

Model

To give you better idea about the structure of my classes here is my Entity Framework model. You can see that events and tags have many-to-many relationship defined between them.

In database I have one table between events and tags but as this table contains primary key that is 100% made up of foreign keys of events and tags table then Entity Framework is able to create many-to-many mapping automatically without creating additional object for relation.

You can also see that there is Events navigation property defined for Tag class. It is not good idea to create more navigation paths than you need and in the case of Tag class we need this navigation property.

Tag cloud solution

To create tag cloud we need to go through the following steps:

  1. Create Tag table and bind it to Event.
  2. Update your Entity Framework model to reflect new changes made to database.
  3. Add some classes that hold tag cloud data (TagCloud is container class that keeps collection of MenuTag objects).
  4. Create extension method to Html class that generates tag cloud.

I started with code I found from Mikesdotnetting blog posting Creating a Tag Cloud using ASP.NET MVC and the Entity Framework and worked out my own solution. Referred posting was great help for me and let’s say thanks to author for sharing his ideas with us.

Tag cloud implementation

As a first thing let’s create the class that holds tag data. I named this class as MenuTag.


public class MenuTag

{

    public string Tag;

    public int Count;

}


Tag is the title of tag and Count shows how many events are tagged with this tag.

Next we need the class that packs everything up and provides us with tag rank calculation. For that I defined class called TagCloud.


public class TagCloud

{

    public int EventsCount;

    public List<MenuTag> MenuTags = new List<MenuTag>();

 

    public int GetRankForTag(MenuTag tag)

    {

        if (EventsCount == 0)

            return 1;

 

        var result = (tag.Count * 100) / EventsCount;

        if (result <= 1)

            return 1;

        if (result <= 4)

            return 2;

        if (result <= 8)

            return 3;

        if (result <= 12)

            return 4;

        if (result <= 18)

            return 5;

        if (result <= 30)

            return 6;

        return result <= 50 ? 7 : 8;

    }

}


Now we have to add new method to our Entity Framework model that asks data from database and creates us TagCloud object. To add new methods to model I am using partial classes.


public partial class EventsEntities

{

    private IQueryable<Event> ListPublicEvents()

    {

        var query = from e in events

                    where e.PublishDate <= DateTime.Now

                          && e.Visible

                    orderby e.StartDate descending

                    select e;

        return query;

    }

    public TagCloud GetTagCloud()

    {

        var tagCloud = new TagCloud();

        tagCloud.EventsCount = ListPublicEvents().Count();

        var query = from t in Tags

                    where t.Events.Count() > 0

                    orderby t.Title

                    select new MenuTag

                    {

                        Tag = t.Title,

                        Count = t.Events.Count()

                    };

        tagCloud.MenuTags = query.ToList();

        return tagCloud;

    }

}


And as a last thing we will define new extension method for Html class.


public static class HtmlExtensions

{ 

    public static string TagCloud(this HtmlHelper helper)

    {

        var output = new StringBuilder();

        output.Append(@"<div class=""TagCloud"">");

 

        using (var model = new EventsEntities())

        {

            TagCloud tagCloud = model.GetTagCloud();

 

            foreach(MenuTag tag in tagCloud.MenuTags)

            {

                output.AppendFormat(@"<div class=""tag{0}"">",
                                    tagCloud.GetRankForTag(tag));

                output.Append(tag.Tag);

                output.Append("</div>");

            }

        }

 

        output.Append("</div>");

 

        return output.ToString();

    }

}


And you are almost done. I added my tag cloud to my site master page. This is how what you should write to show tag cloud in your view:

    @Html.Raw(Html.TagCloud())

You can also go on and create partial view but then you have to give data to it through your view model because writing code behind views is not a good idea. If you look at my extension method you will see it’s simple and short and that’s why I prefer to keep it this way.

Conclusion

ASP.NET MVC and Entity Framework make it easy to create modern widgets for your site. Just keep as close to ASP.NET MVC framework as you can and orchestrate it with Entity Framework models. In this posting I showed you how to create simple tag cloud component that plays well together with ASP.NET MVC framework. We created some classes where we keep our data. Tag cloud data is coming from Entity Framework model and tag cloud is included in views using Html extension method.

ASP.NET MVC 3: Using controllers scaffolding
 

ASP.NET MVC 3 Tools Update introduces support for controllers scaffolding with views and data access code. Right now I am building one very simple web site for free tech events and as I am building it on ASP.NET MVC 3 I have good testing polygon right here. In this posting I will show you how controller scaffolding works and what is the end result.

About my solution

I am building simple tech events web site and here is my very simple model that is still under heavy construction.

ASP.NET MVC 3: Simple event model

If you have built something like this before then you should also be able to see one interesting output that I have to generate – namely event schedule. Cool, this is something I can blog about later.

Adding controller for events management

Under admin section I want to be able to manage the events. So, let’s add new controller for events. This is new Add Controller dialog and I have selected template that is based on Entity Framework (yes, I am using EF in this project).

ASP.NET MVC 3: New controller adding dialog

Also notice that there is dropdown for data context class. This dropdown is filled automatically and it provides you with Entity Framework models you have in your projects.

Controller with data access methods

ASP.NET MVC 3: Controller and views generated by controller scaffolding feature

Image on right shows what was generated when I hit Add button. There is controller class with all methods to manage events and… this is all buggy because event, when lower cased, is keyword of C#. Here’s the example:


[HttpPost]

public ActionResult Create(Event event)

{

    if (ModelState.IsValid)

    {

        db.events.AddObject(event);

        db.SaveChanges();

        return RedirectToAction("Index"); 

    }

 

    return View(event);

}


I suppose I doesn’t compile without renaming some variables. :)

After fixing the variable names and removing comments generated by default I have controller class that looks like this.


public class AdminEventsController : Controller

{

    private EventsEntities db = new EventsEntities();

 

    public ViewResult Index()

    {

        return View(db.events.ToList());

    }

 

    public ViewResult Details(int id)

    {

        Event evt = db.events.Single(e => e.Id == id);

        return View(evt);

    }

 

    public ActionResult Create()

    {

        return View();

    }

 

    [HttpPost]

    public ActionResult Create(Event evt)

    {

        if (ModelState.IsValid)

        {

            db.events.AddObject(evt);

            db.SaveChanges();

            return RedirectToAction("Index"); 

        }

 

        return View(evt);

    }

 

    public ActionResult Edit(int id)

    {

        Event evt = db.events.Single(e => e.Id == id);

        return View(evt);

    }

 

    [HttpPost]

    public ActionResult Edit(Event evt)

    {

        if (ModelState.IsValid)

        {

            db.events.Attach(evt);

            db.ObjectStateManager.ChangeObjectState(evt,
               
EntityState.Modified);

            db.SaveChanges();

            return RedirectToAction("Index");

        }

        return View(evt);

    }

 

    public ActionResult Delete(int id)

    {

        Event evt = db.events.Single(e => e.Id == id);

        return View(evt);

    }

 

    [HttpPost, ActionName("Delete")]

    public ActionResult DeleteConfirmed(int id)

    {           

        Event evt = db.events.Single(e => e.Id == id);

        db.events.DeleteObject(evt);

        db.SaveChanges();

        return RedirectToAction("Index");

    }

 

    protected override void Dispose(bool disposing)

    {

        db.Dispose();

        base.Dispose(disposing);

    }

}


As you can see then most of dirty work is already done for you. All you have to do is some little tweaking of methods so they better fit your needs.

Views

With controller we also got views for controller actions. Views are generated like they were before. Here is the example of list view of events that is generated by default.

ASP.NET MVC 3: Default list view for events
Click on image to view it at original size.

So, nothing special for views has happened but they are generated and work well.

Conclusion

ASP.NET MVC 3 Tools Update offers controllers scaffolding feature that helps to generate CRUD methods for controllers and appropriate views. It is very cool that Entity Framework models are supported and ASP.NET MVC is able to generate working code that you can use right after generating it. Although this code usually needs some tweaking and modifications it is still useful because it saves you some time.

ASP.NET MVC: Defining short URL-s for root level pages
 

Short URL-s are more and more important part of page usability as mobile internet is growing. Long URL-s are not convenient to type due to small keyboards and screens of mobile devices. Also short URL-s are easier to remember and using well chosen short URL-s your pages may also get better rankings in search engines indexes. In this posting I will show you how to create short URL-s for ASP.NET MVC pages.

Default routes

Routes used by default are part of ASP.NET MVC applications right from start. After creating new ASP.NET MVC application you can find the following RegisterRoutes() method from Global.asax file.


public static void RegisterRoutes(RouteCollection routes)
{

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  

    routes.MapRoute(

        "Default", // Route name

        "{controller}/{action}/{id}", // URL with parameters

        new { controller = "Home", action = "Index",
              id =
UrlParameter.Optional }
// Parameter defaults

    ); 

}


IgnoreRoute() call here sais to ASP.NET MVC that *.axd files need no processing. Call of MapRoute() method creates new route and sets the following default values:

  • controller – if controller name cannot be found from URL then take HomeController,
  • action – if action cannot be found from URL then take Index() as default action,
  • id – it is optional and may be omitted.

We can define other routes too if we need.

Shortening URL of About page

As all ASP.NET MVC applications get by default also page called default we can use it to analyze its default URL and create shorter URL after that. By default, About page has the following URL:

http://yourhost/Home/About

As Home controller is all about “default” pages as activities that happen on root level of site we don’t have any good reason to keep word Home in URL. In SEO terms it increases the distance of page title and in some cases shorter URL-s perform better in search engines.

To get short URL like this:

http://yourhost/about

add the following route definition to previously shown method, right before last route definition.


routes.MapRoute(

    "ShortAbout",

    "about",

    new { controller = "Home", action="about" }

);


When you run your application you can see that ASP.NET MVC generates short URL for About page automatically. 

This solution works well if you have only some pages under root level of site. This is default case for many pages. Of course, it is possible to write more code and have more advanced routing that handles all short URL cases but right now I think this way you move quicker.

Conclusion

ASP.NET offers powerful routing mechanism and MVC framework makes good use of it. Sometimes we may need better URL-s for root level pages than the ones that are generated by MVC framework by default. There may be pages like About, Terms, Join, Log in etc. If we don’t have many pages on root level we can easily define new routes for these pages that offer shorter URL-s that are easier to remember and easier to type on mobile devices. Also search engines may give better rankings to our pages if we don’t use longer URL-s. We saw that it was easy to add new routes to routes collection for pages that need shorter URL. Our method works as far as there are not much pages on root level of site.

Posted: Apr 17 2011, 11:27 AM by DigiMortal | with 5 comment(s) |
Filed under: , ,
ASP.NET MVC 3: Intranet Application template
 

ASP.NET MVC 3 Tools Update introduced new project template called Intranet Application.  The main difference between internet and intranet application templates is the way how users are authenticated. In this posting I will talk about Intranet Application template and compare it to Internet Application template. Also I will give you references to guides that help you configure your intranet application.

Creating new intranet application is easy. Just create new ASP.NET MVC 3 web application and select Intranet Application as template.

ASP.NET MVC 3 Tools Update: Create new intranet application

Intranet application is practically empty web application with home controller and support for Windows authentication. As Windows authentication is optional choice when configuring web application you should do some manual configuring to get intranet application run.

ASP.NET MVC 3 Tools Update: Intranet application in action

As intranet application uses Windows authentication it doesn’t need sign-in, registering and password reminder forms. Also it does not need model classes for authentication. By all other parts the intranet application is the same as internet application.

Enabling Windows authentication

ASP.NET MVC 3 Tools Update: Configure Windows authenticationIf you are using IIS Express then follow these steps:

  1. Right click on the project in Visual Studio and select Use IIS Express.
  2. Click on your project in the Solution Explorer to select the project.
  3. If the Properties pane is not open, make sure to open it (F4).
  4. In the Properties pane for your project:
    1. Set "Anonymous Authentication" to "Disabled".
    2. Set "Windows Authentication" to "Enabled".

Now try to run your application to see if you are correctly authenticated.

If you have other server than IIS Express then take a look at the following MSDN library page: How to Create an Intranet Site Using ASP.NET MVC.

Posted: Apr 14 2011, 01:34 AM by DigiMortal | with 3 comment(s)
Filed under: ,
ASP.NET MVC 3 Tools Updated released!
 

ASP.NET MVC 3 Tools Update is out and it introduces some new cool things. In this posting I will give you brief overview of new stuff available in ASP.NET MVC 3 Tools Update. More specific posts about new features will follow.

New features in brief are following:

  • "Add Controller" dialog box can now scaffold controllers with views and data access code (available scaffolding templates: Empty controller, Controller with empty read/write actions, Controller with read/write actions and views, using Entity Framework.
  • New application template called “Intranet Application”.
  • Generating mark-up using HTML5.
  • Project templates now include Modernizr 1.7.
  • Project templates now include ADO.NET Entity Framework 4.1 as a pre-installed NuGet package.
  • Project templates include JavaScript libraries as pre-installed NuGet packages.

Click here to download ASP.NET MVC 3 Tools Update and try it out.

Posted: Apr 13 2011, 04:32 PM by DigiMortal | with 7 comment(s)
Filed under: ,
ASP.NET MVC: Using NonActionAttribute to restrict access to public methods of controller
 

Public non-action methods in ASP.NET MVC controllers are source of problems because they can be called by user when not handled carefully. Same time you may need public methods on controllers for some other reasons (some UI framework, testability problems, things you cannot change etc). In this posting I will show you how to handle controller methods properly.

Calling controller methods

Public methods of controller are called controller actions and these actions are mapped to URL-s using routes. Take a look at the following code.


public ActionResult Index() {    
ViewBag.Message =
"Welcome to ASP.NET MVC!"
;    
return View(); }

You can see here two controller methods. One of them is Index() and it is expected to be called by browser. The other one – DoInternalStuff() – is intended only for internal use.


public void DoInternalStuff()
{
     Response.Write(
"We are doing internal stuff here!");
     Response.End();
}

Although these examples are primitive ones they let us illustrate the situation very well.

Calling non-action method

As you can guess then first method returns out-of-box default page that comes with ASP.NET MVC web application project. But what happens when we try to call this other method? The result is here.

ASP.NET MVC: Calling non-action method

We can call this method directly through browser and if it contains arguments we may be able to inject them too under certain circumstances. This is something we don’t want to happen.

Restricting access to non-action methods

To restrict access to non-action method you must use NonActionAttribute to notify MVC framework that given controller method is not action. The code is here:


[NonAction]
public void
DoInternalStuff()
{
     Response.Write(
"We are doing internal stuff here!");
     Response.End();
}

Now when we try to run DoInternalStuff() over URL we get the error 404 as response to request.

Conclusion

There are situations where non-action controller methods are used and there may even exist situations where visibility of these methods cannot be changed. To avoid users to invoke those methods directly – this can be considered as security hole – we have to say MVC framework using NonActionAttribute that these methods are not controller actions.

More Posts