RadChart with .NET MVC

I have a webform app that I converted to a webform/mvc hybrid. Everything was fine until I tested the Telerik RadCharts on the existing webform pages. It had worked before the conversion. Now whenever the chart was supposed to load, I was confronted with this error message:

Error loading RadChart image. You may also wish to check the ASP.NET Trace for further details. Display stack trace?

Clicking “OK” simply took me to a 404 page. I did notice the url of this was http://localhost:11239/reports/ChartImage.axd?UseSession=true&ChartID=139df24e-1578-44d3-988b-c66f2d7df98c_chart_ctl00$MainContent$ReportChart1&imageFormat=Png&random=0.725656411482793

Somehow MVC routing disrupted the RadChart handler. To fix this, you need to explicitly define the HttpHanderUrl property of the RadChart.

ReportChart1.HttpHandlerUrl = ResolveUrl("~/ChartImage.axd");

That should fix it!

Add MVC capabilites to ASP.NET webform application

Because they both are built on the same framework, it’s pretty simple to get the two to play nice together. I used this as a guide: http://guy.dotnet-expertise.com/PermaLink,guid,4f5a8ea1-1f90-4b32-a635-1d73d906aeca.aspx. It’s an old article but it worked for me. I’m using Visual Studio 2010, .NET 4.0 and MVC 3 with Razor.

The steps are as follows:

Add the following 3 references to your project:
System.Web.Abstraction
System.Web.Mvc (be aware of what DLL version you’re adding)
System.Web.Routing

Modify the project’s web.config. The easiest way is to create a new MVC project and copy over the value from there. You need to copy over the following sections, but don’t overwrite the existing values:
Compilation
Pages
HttpHandlers (this didn’t apply for me because it wasn’t in the MVC web.config. Might be a .NET 4.0 or MVC 3 thing.)
System.WebServer
Runtime

Next modify Global.asax Application_Start method to perform the same functions as your temp MVC functions.

Then copy the web.config in the View folder of the MVC project and paste it in the View folder of your webform project. Also don’t forget to copy any scaffolding files such as _Layout.cshtml and _ViewStart.cshtml.

Finally, you need to let Visual Studio know that your project now handles MVC pages as well. This will allow you to use the IDE to create Controller, Views, and other MVC goodies. Open the temp MVC project file in notepad and look for the <ProjectTypeGuids> section. Copy that guid and add it to your webform project folder. The guid in my project is {E53F8FEA-EAE0-44A6-8774-FFD645390401}.

That’s it. Now you should be able to create MVC files just was if the webform project was an MVC project itself.

WCF basicHttpBinding – 504 Gateway Timeout

I had a WCF service secured with SSL, using wsHttpBinding, Message security mode, and UserName authentication. Everything worked find because I created the client app in VisualStudio and it automatically generated the appropriate tags in web.config. I was able to connection, authenticate and call methods without issue.

But now I need to adjust the service to allow clients of other technologies to connect to it…more specifically PHP. PHP can’t connect to a service that uses wsHttpBinding. It has to be basicHttpBinding because it conforms to a broader standard.

The first thing to do is change system.serviceModel/services/service binding attribute to “basicHttpBinding”. Then create a <basicHttpBinding> node under system.serviceModel/bindings. Because we can’t use the Message security mode with basicHttpBinding, it needs to be changed to TransportWithMessageCredential. And that’s basically it for the service.

Now just publish it, connect to it from your client and call it a day. Well it didn’t go that smoothly for me. My client app I create for the original wsHttpBinding service was griping with an error: The remote server returned an error: (504) Gateway Timeout. Update the service reference? Nope that didn’t help. Remove and create the service reference? Nope, same error. So then I tried playing with the service configuration to no avail.

Finally I decided to read the stack trace and saw “There was no endpoint listening at https://myremoteservername/service.svc that could accept the message. This is often caused by an incorrect address or SOAP action.” Weird, how did it know the name of my server? I went back to my client’s web.config and looked at the endpoint VS created with I added the service reference. Indeed the address contained the server name! I changed it to the publicly accessible domain name and it works.

For some reason, when VS references a service with basicHttpBinding, it uses the server name. But I have no idea how it got the name in the first place. When adding the reference, I entered the public (correct) .svc url.

I’ll have to check with our network guy about it but I’m happy it’s finally working.

C# and VB.NET in the same App_Code folder

I learned something cool today. I’m taking over a site that’s been written in VB.NET. While making some major modifications, I had to create a few new util classes. The problem is, the existing classes in the App_Code folder was written in VB.NET and I like to code in C#. If you try to compile a site that has two different languages in the App_Code directory, it won’t work. I found this article that says it can be done it just two steps. The trick is to create two subdirectories in App_Code; one to house each language; then edit your web.config to let the compiler know what to expect.

In an ideal environment this works. The website will compile fine. But I ran into another issue after doing this. After I created my two subdirectories (CS_Code and VB_Code), I moved the existing VB classes into VB_Code. The problem is, there are xsd files that I need to leave in the App_Code folder. These DAL files need to be in the root App_Code directory because it needs to be accessed by all the classes (VB and C#). But after I moved the VB classes into VB_Code, the VB classes can no longer see the xsd classes.

I feel like this is an issue that can easily be resolved but it’s past midnight and maybe my mind isn’t thinking straight. Also keep in mind that the project is a Website and not a Web Application. I’ve ran into issues in the past where the nuances between the two made a world of difference. It’s shame this project is due tomorrow. Comment/suggestions welcome*.

*and encouraged

Ensuring image quality when resizing in .NET

I needed to create a web page where users can upload photos. In turn, these photos will be resized into three different dimensions (small, medium, and large) and displayed on the site. The original code I was using to resize the images was pretty much hit or miss. Often times the resulting image was blurry and/or pixelated. The original code took the file from the file upload control and saved it as a bitmap. Then it used the GetThumbnailImage method to resize the image. Here is a sample.

System.Drawing.Image.GetThumbnailImageAbort myCallBack = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallBack);
System.Drawing.Bitmap bitmap = new Bitmap(fileUpload.InputStream);
System.Drawing.Image newImage = bitmap.GetThumbnailImage(600, 800, myCallBack, IntPtr.Zero);
newImage.Save(“c:\resizedImage.jpg”);
newImage.Dispose();

private static bool ThumbnailCallback()
{
return false;
}

The callback method is called if the resize fails but I’m not sure what the IntPtr.Zero does. VS’s intellisense states “Must be System.IntPtr.Zero”, so who am I to argue. The code is very simple but not very effective. Today I found a better method. This time using an Image object instead and resizing it with the Graphics class. Finally, I use the Bitmap object to save the image.

System.Drawing.Image image = Bitmap.FromStream(file.InputStream);
System.Drawing.Imaging.ImageFormat imageFormat = image.RawFormat;
Size size = new Size(600, 800);
bitmap = new Bitmap(image, size.Width, size.Height);

Graphics resizer;
resizer = Graphics.FromImage(bitmap);
resizer.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
resizer.DrawImage(image, 0, 0, size.Width, size.Height);

bitmap.Save(“c:\resizedImage.jpg”, imageFormat);
bitmap.Dispose();
image.Dispose();

There are a few important key elements here. First is the InterpolationMode. HighQualityBicubic gives you the best quality but I find HighQualityBilinear decreases the size by at least a few KB and I couldn’t tell the difference between the two just by looking at it. Also, when using bitmap.Save(), the image format parameter is not required but it makes all the difference. For example, I resized a 2112 x 2816 pixel to 600 x 800. If I didn’t specify the image format the size was reduced from 2.2 MB to 1.1 MB. When I did specify the image format, the resulting file size was 58 KB! Again, I could barely tell the difference between the two resulting images. And finally, always clean up after yourself. Dispose of objects you no longer need, especially if they deal with streams.

WebDAV and recurring events in Exchange 2003

I’m in the process of building a web app to pull calendar events from Exchange 2003 and display them on a page. With some research and a lot of trial and error, I was able to put together bit and pieces of examples on the web and get most of it done. The only problem is that recurring events were not being pulled. It turns out that if a recurring event is schedule to recur ad infinitum, the WebDAV query will not retrieve the event unless a start date and end date is specified. Below is part of the code.

public void Authenticate(string authUri, string destinationUri, string username, string password)

{

// Create the web request body:

string body = string.Format(“destination={0}&username={1}&password={2}”, destinationUri, username, password);

byte[] bytes = Encoding.UTF8.GetBytes(body);

// Create the web request:

HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(authUri);

request.Method = “POST”;

request.ContentType = “application/x-www-form-urlencoded”;

request.CookieContainer = new CookieContainer();

request.ContentLength = bytes.Length;

// Create the web request content stream:

using (Stream stream = request.GetRequestStream())

{

stream.Write(bytes, 0, bytes.Length);

stream.Close();

}

// Get the response & store the authentication cookies:

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

if (response.Cookies.Count < 2)

throw new AuthenticationException(“Login failed. Is the login / password correct?”);

cookies = new CookieContainer();

foreach (Cookie myCookie in response.Cookies)

{

cookies.Add(myCookie);

}

response.Close();

}

public List<CalendarEvent> GetCalendar(string uri, DateTime startDate, DateTime endDate)

{

List<CalendarEvent> eventList = new List<CalendarEvent>();

HttpWebRequest request;

WebResponse response;

byte[] bytes;

// Note that deep traversals don’t work on public folders. In other words, if you

// need to dig deeper you’ll need to split your query into multiple requests.

string format =

@”<?xml version=””1.0″”?>” +

@”<D:searchrequest xmlns:D = “”DAV:””>” +

@”<D:sql>” +

@”SELECT “”urn:schemas:calendar:dtstart””, ” +

@”””urn:schemas:calendar:dtend””, ” +

@”””urn:schemas:calendar:location””, ” +

@”””urn:schemas:httpmail:subject””, ” +

@”””urn:schemas:httpmail:htmldescription””, ” +

@”””urn:schemas:httpmail:to””, ” +

@”””urn:schemas:calendar:organizer””, ” +

@”””DAV:parentname”” ” +

@”FROM ” +

@”Scope(‘SHALLOW TRAVERSAL OF “”{0}””‘) ” +

@”WHERE ” +

@”NOT “”urn:schemas:calendar:instancetype”” = 1 ” +

@”AND “”DAV:contentclass”” = ‘urn:content-classes:appointment’ ” +

@”AND “”urn:schemas:calendar:dtstart”” &gt;= ‘{1}’ ” +

@”AND “”urn:schemas:calendar:dtend”” &lt;= ‘{2}’ ” +

@”</D:sql>” +

@”</D:searchrequest>”;

string fullQuery = String.Format(format, uri, DateTime.Now.AddYears(-1).ToString(“yyyy/MM/dd”), DateTime.Now.AddYears(1).ToString(“yyyy/MM/dd”));

bytes = Encoding.UTF8.GetBytes(String.Format(fullQuery, uri, startDate, endDate));

// Use the authorization cookies we stored in the authentication method.

request = (HttpWebRequest)HttpWebRequest.Create(uri);

request.CookieContainer = cookies;

request.Method = “SEARCH”;

request.ContentLength = bytes.Length;

request.ContentType = “text/xml”;

using (Stream requestStream = request.GetRequestStream())

{

requestStream.Write(bytes, 0, bytes.Length);

requestStream.Close();

}

response = (HttpWebResponse)request.GetResponse();

using (Stream responseStream = response.GetResponseStream())

{

// Parse the XML response to find the data we need.

XmlDocument document = new XmlDocument();

document.Load(responseStream);

XmlNodeList subjectNodes = document.GetElementsByTagName(“e:subject”);

XmlNodeList startTimeNodes = document.GetElementsByTagName(“d:dtstart”);

XmlNodeList endTimeNodes = document.GetElementsByTagName(“d:dtend”);

XmlNodeList organizerNodes = document.GetElementsByTagName(“d:organizer”);

XmlNodeList bodyNodes = document.GetElementsByTagName(“e:htmldescription”);

XmlNodeList locationNodes = document.GetElementsByTagName(“d:location”);

XmlNodeList toNodes = document.GetElementsByTagName(“e:to”);

string bodyStart = “<!– Converted from text/rtf format –>\r\n\r\n”;

string bodyEnd = “\r\n\r\n</BODY”;

for (int index = 0; index < subjectNodes.Count; index++)

{

string subject = subjectNodes[index].InnerText;

string organizer = HttpContext.Current.Server.HtmlEncode(organizerNodes[index].InnerText.Replace(“\””, “”).Replace(“<“, “(“).Replace(“>”, “)”));

DateTime startTime = DateTime.Parse(startTimeNodes[index].InnerText);

DateTime endTime = DateTime.Parse(endTimeNodes[index].InnerText);

string body = bodyNodes[index].InnerText;

string location = locationNodes[index].InnerText;

//CalendarEvent is my custom class

CalendarEvent ev = new CalendarEvent();

ev.StartTime = startTime;

ev.EndTime = endTime;

ev.Subject = subject;

ev.Organizer = organizer;

ev.Body = body;

ev.Location = location;

eventList.Add(ev);

}

}

response.Close();

return eventList;

}