Adding the ASP.net Web API to a Web Forms website

The latest version of the MVC framework comes with ASP.NET Web API support and that’s great. But if like me, you’ve got a web forms website where you want to leverage the capabilities of the Microsoft Web Api, then there are some manual things you need to do.

The first question you need to ask yourself is why do you want the Web Api kit in the first place. For me, my main website runs on web form and it’s too much work at the moment to migrate it to MVC. Other new projects are being done in MVC and I need to way to communicate with the new website. For example, I’ve got a central database which stores user details and I need to get information on a particular user by querying the main website through a web service.  You could very well get the same information by querying the database directly but what if you had business logic as well which filters data before it is displayed? For my problem, I needed to get the total points of a particular user by sending off the UserId.

If you right click on your ASP.NET website in Solution Explorer (Visual Studio) and click on “Add New Item”, you can select the “Web API Controller Class” which I’ve renamed as UserController:

user controller

I didn’t need all those things in the controller, so I removed all and now it looks like this:


public class UserController : ApiController
{
 // GET api/<controller>/5
 public int Get(int id)
 {
 ISession session = NHibernateSessionManager.CreateSession();
 User user = new Repository<User>(session).GetById(id);
 NHibernateSessionManager.CloseSession(session);

return user.Points;
 }
}

But before you could actually compile your site, you need to add the following codes to your Global.ascx file:


void Application_Start(object sender, EventArgs e)
 {
 RouteTable.Routes.MapHttpRoute(
 name: "DefaultApi",
 routeTemplate: "api/{controller}/{id}",
 defaults: new { id = System.Web.Http.RouteParameter.Optional }
 );
 }

This means that if your website is http://www.mydomain.com, you will be able to access your web api at http://www.mydomain.com/api and in my case for my controller it would be:

http://www.mydomain.com/api/user/5 where 5 is the UserId of the user I want to retrieve the points for.

It was as simple as this and I couldn’t believe it.

How to call the Web API url in code

In order to consume the web api, you can use the HttpClient class. For example in my MVC project, I added the following method:


int _points;

public void GetUserPoints(int userId)
 {
 try
 {
 HttpClient client = new HttpClient();
 client.BaseAddress = new Uri(System.Configuration.ConfigurationManager.AppSettings["ApiUrl"]);

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = client.GetAsync(String.Concat("user/", userId)).Result; // Blocking call!
 if (response.IsSuccessStatusCode)
 {
 // Parse the response body. Blocking!
 _points = response.Content.ReadAsAsync<int>().Result;
 }
 }
 catch (Exception ex)
 {
 _points = 50;
 }
 }

You’ll need the following namespaces for it to work:

  • using System.Net.Http;
  • using System.Net.Http.Headers;

Problem getting the Web Api to work on the live server

After everything was tested, I uploaded the new asp.net website which contained my web api interface onto my Windows 2008 box and I was horrified when it threw an error. It was something to do with a missing dll. It happened because the DLL was not found in the GAC while on my local machine that was the case. There are many ways to solve the problem but for me the easier thing was to install the MVC 4 framework on the Windows server to rectify the problem. And that worked!

Error 404 for woff file extension

On one of my website, I was using a special font, the Web Open Font Format (.woff) and while all was working fine in all browsers, I noticed Google Chrome was returning a 404 HTTP Status Code. This meant that it was not able to find the file. I looked into the path given by the style sheet and there it was. So no problem there but what was actually causing the error?

It was my server not knowing what to do with this extension. I was running IIS7.5 and it was not configured to process .woff files. Therefore you either need to add this MIME type to your server by specifying application/x-font-woff to be used for that extension.

woff to iis

Or you can just insert the following lines in your web.config file:


<system.webServer>
 <staticContent>
  <mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
 </staticContent>
</system.webServer>

I opted for the second option (web.config modification) and Chrome stopped complaining about the missing .woff files.

Fixing Adsense stats not showing up in Google Analytics

I used to be highly involved in optimising Adsense on my sites but when Google Panda struck, that was the last thing on my mind. Before I was getting an increasing amount of visitors every month and there was a steady income coming in but since April 2011, things have changed. I’m not going into the details of this  but a week ago, I decided I must find out what webpages were earning me the most on my sites.

My Adsense account has always been linked to my Analytics account since that functionality was made available but for some reason, only my main domain was being reported in. I double checked my settings in both Adsense & Analytics and they were correct. So I was confused. The report showed only partial earnings and when I investigated, I found statistics for one sub domain was missing.

It was then that I realised the problem was due to a modification I made to my GA code when I wanted to track multiple sub domains with the same code. This is the extra line I had:

_gaq.push([‘_setDomainName’, ‘mydomain.com’]);

To rectify the problem, I had to add the following line to my adsense code:

google_analytics_domain_name=”mydomain.com”;

Therefore your adsense block will look like this:


<script type="text/javascript"><!--
google_analytics_domain_name="mydomain.com";
google_ad_client = "ca-pub-123456789";
/* Custom Adsense Unit */
google_ad_slot = "1000000";
google_ad_width = 336;
google_ad_height = 280;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>

Analytics is now displaying the proper stats for Adsense and I can now see which URLs are bringing in the more clicks and how much the clicks are worth. This will help me optimise these webpages fully and also give me the right insights to monetise other pages of my site.

Note that the Adsense programme does not allow you to modify the ad codes. Therefore you might need to have a separate javascript call as follows:

<script type=”text/javascript”>
google_analytics_domain_name=”mydomain.com”;
</script>

How to pass parameters to the ViewModel in MVC

On a user account page, I had to display specific information regarding the logged in user. Things like Name, Age etc. I designed a ViewModel called UserAccount which takes in a UserId as a parameter to its contructor and based on that value, the VM pulls information from the database for that specific user. Something like this:


public class UserAccount

{

public string Name { get; set;}

public int Age { get; set; }

public UserAccount(int userId)

{

User user = GetUserFromRepository(userId);

Name = user.Name;

Age = user.Age;

}

}

All information I needed was provided by the VM but when it came to attaching this VM to the View, I got stuck. I need to mention I’m quite new to MVC but then I managed to find the solution to this:


public ActionResult MyAccount()
 {
 if (!Helper.IsUserLoggedIn())
 {
 return Redirect(Helper.GetLoginPageWithRedirect());
 }
 else
 {
 var vm = new Core.ViewModel.UserAccount(Helper.GetUserIdFromSession());

return View(vm);
 }
 }

What this does is first check whether the user is actually logged in. If not, it redirects the user to the login page because they should not  be able to access the account page without being signed in. Since you can actually pass in an object when returning a View, you can already initialise your object through constructor injection and then do “return View(YourAlreadyInitialisedObject”);” That saved me from writing extra lines of codes and it works brillantly.