Tuesday, September 25, 2012

Calling Web Services Using BasicAuth From .NET

At work I have to consume lots of web services from all over the place. They come in many flavors: .NET, Java, etc.

When calling Java Web Services written in WebSphere from .NET using BasicAuth (username and password), sometimes the credentials are not asked from the host and the return code is a 401:

Web Exception

The best way to fix this annoying problem is to create a partial class with the same name as the one generated by WSDL.exe and override the GetWebRequest(Uri uri) function.

Creating a Web Service Client:

WSDL.exe

Creating partial class with overridden method: 

public partial class Service
{
    public string Username { get; set; }
    public string Password { get; set; }

    private void setBasicAuthHeader(WebRequest req)
    {
        string authInfo = Username + ":" + Password;
        authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
        req.Headers["Authorization"] = "Basic " + authInfo;
    }

    protected override WebRequest GetWebRequest(Uri uri)
    {
        this.Credentials = new NetworkCredential(Username, Password);
        WebRequest request = base.GetWebRequest(uri);
        setBasicAuthHeader(request);
        return request;
    }
}

The code above will override the GetWebRequest method by adding an "Authorization" header containing the username and password. WebSphere looks for this header on basic authorization. This should get rid of the 401 return code.

Calling the Web Service:

void CallService()
{
    Service service = new Service();

    service.Username = "username";
    service.Password = "password";

    Result result = service.GetData();
}

And this is all there is to it. Now you can call any web service that accepts basic auth.

Monday, September 17, 2012

Creating Interactive Charts with ASP.net MVC

Chart Control

Problem at Hand:

Many ASP.net developers are used to creating charts using the .NET built-in Chart Controls, but how about MVC developers? Are they out of luck?

A couple weeks ago I was looking for a way to generate nice looking charts for an application I'm working on and I found out that while there are several ways to use the .NET chart controls in MVC, most of the implementations lack interactivity and therefore were useless for the application I wanted to create. I found an example from Daniel A Hill using a custom chart action result and it looked promising, but it lacked interactivity as well, so I started looking for a way to make my own Action that would do what I wanted.

If we look at the underlying HTML that is generated by chart controls, we see that it consists of a <img> and a <map>, so all we need to do is create both of these and we will have our interactive controls.

Controller Action:

public ActionResult Chart()
{
    var chart = buildChart();
    StringBuilder result = new StringBuilder();
    result.Append(getChartImage(chart));
    result.Append(chart.GetHtmlImageMap("ImageMap"));
    return Content(result.ToString());
}

Utility Functions:

private Chart buildChart()
{
    // Build Chart
    var chart = new Chart();

    // Create chart here
    chart.Titles.Add(CreateTitle());
    chart.Legends.Add(CreateLegend());
    chart.ChartAreas.Add(CreateChartArea());
    chart.Series.Add(CreateSeries());

    return chart;
}

private string getChartImage(Chart chart)
{
    using (var stream = new MemoryStream())
    {
       string img = "<img src='data:image/png;base64,{0}' alt='' usemap='#ImageMap'>";
       chart.SaveImage(stream, ChartImageFormat.Png);
       string encoded = Convert.ToBase64String(stream.ToArray());
       return String.Format(img, encoded);
    }
}

Then in your View code:

@{ Html.RenderAction("Chart"); }

Conclusion:

This is all there is to it. One caveat is that you MUST call chart.SaveImage() before calling chart.GetHtmlImageMap(), otherwise it will throw an Exception, but if you are careful in doing that, it should all just work.To see an example of the new controller in action, head over to MVC Chart. To see the whole source code, take a look at my github repository.