Showing posts with label WebAPI. Show all posts
Showing posts with label WebAPI. Show all posts

Monday, September 1, 2014

JQuery Consume ASP.NET Web API

Today I want to share how to consume ASP.NET Web API by using jQuery. How to do that? Just send HTTP GET, POST, PUT, DELETE request to the Web API with JSON format content. I will use the same address book Web API for testing which I had created in my previous post.

First, add JQuery to your web project by using NuGet.


At the UI designer page, create all the necessary form and fields. I reuse the same UI which I did for my previous post, and added a few extra buttons with JQuery label. These buttons are using AJAX to invoke the Web API.



The following are the Javascript / JQuery that use to invoke the Web API:

HTTP GET

The following method send HTTP GET request to the Web API and get the response data to form a custom grid view (table):

function Get() {
    $.ajax({
        type: 'GET',
        url: 'http://localhost:5593/api/AddressBook',
        dataType: 'json',
        success: function (response) {
            var addressBookList = response;
            CreateTableColumns();
            $.each(addressBookList, function () {
                $('#addressBookTable')
                    .append($('<tr>')
                    .append('<td>' + this.ID + '</td>')
                    .append('<td>' + this.FirstName + '</td>')
                    .append('<td>' + this.LastName + '</td>')
                    .append('<td>' + this.Contact + '</td>')
                    .append('</tr>'));
            });
        }
    });

}

HTTP POST

The following method send HTTP POST request to the Web API to create new record:

function Post() {
    var addressBook = {
        ID: $('input[type="text"][id="ID"]').val(),
        FirstName: $('input[type="text"][id="firstName"]').val(),
        LastName: $('input[type="text"][id="lastName"]').val(),
        Contact: $('input[type="text"][id="contact"]').val()
    };
    $.ajax({
        type: 'POST',
        url: 'http://localhost:5593/api/AddressBook',
        data: addressBook,
        dataType: 'json',
        success: function () {
            //do something here after posted successfully
            alert('Success! Click the Refresh button to see the effect.');
        }
    });
}

HTTP PUT

The following method send HTTP PUT request to the Web API to update an existing record:

function Put() {
    var addressBook = {
        ID: $('input[type="text"][id="ID"]').val(),
        FirstName: $('input[type="text"][id="firstName"]').val(),
        LastName: $('input[type="text"][id="lastName"]').val(),
        Contact: $('input[type="text"][id="contact"]').val()
    };
    $.ajax({
        type: 'PUT',
        url: 'http://localhost:5593/api/AddressBook/' + addressBook.ID,
        data: addressBook,
        dataType: 'json',
        success: function () {
            //do something here after posted successfully
            alert('Success! Click the Refresh button to see the effect.');
        }
    });
}

HTTP DELETE

The following method send HTTP DELETE request to the Web API to delete an existing record:

function Delete() {
    var id = $('input[type="text"][id="ID"]').val();
           
    $.ajax({
        type: 'DELETE',
        url: 'http://localhost:5593/api/AddressBook/' + id,
        success: function () {
            //do something here after posted successfully
            alert('Success! Click the Refresh button to see the effect.');
        }
    });
}

Basically, the concept is the same. When you use the HttpClient class to invoke the Web API during postback, compare to the AJAX way that uses JQuery, you will get the same result. As long as the client is sending the correct and expected HTTP header and content, the Web API will just accept and process it. And of course the user experience is different between postback and AJAX.

You may think that using HttpClient to call Web API during postback is not efficient because of every Web API call, you need to postback and go through all the ASP.NET page life cycle. However, in a Service Oriented Architecture (SOA) environment, when you are separating the web application and web service, especially the web application is sitting in DMZ while the web service is sitting in safe zone, then you have to consume the Web API (web service) by using server code (HttpClient in ASP.NET), refer to this post for sample code. When you are heavily rely on Javascript, jQuery, Angular.js or any client scripting framework to invoke the Web API, then it is not going to work because the invocation is coming from the client browser, it cannot direct access to the Web API which is sitting in the safe zone protected with firewall. Of course, if your Web API is supposed to expose to public, then it is different story.

If you are interested with my complete source code, feel free to download it from HERE.


Sunday, August 24, 2014

ASP.NET Web Form Model Binding + Web API

Nowadays, many people are talking about Web API and some developers came to me and ask for sample code about how to call an ASP.NET Web API by using the HttpClient class library. Today, I want to share how to send HTTP GET, POST, PUT and DELETE to the ASP.NET Web API from a web page that perform simple CRUD operation.

I have created a very simple address book web application that can display and manipulate the data from the Web API. To begin with the ASP.NET Web API development, create a new empty web project from Visual Studio.



Select the Empty template, as I want to create the latest Web API (version 2.2) by getting the latest assembly from NuGet later.


From the newly created project, open NuGet Package Manager, then search for Microsoft ASP.NET Web API 2.2, then install it.


As I am using the Map HTTP Attribute Routes method to define my routes, therefore, create the class WebApiConfig as follow:

public class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API routes
        config.MapHttpAttributeRoutes();
    }

}

In the same project, add new Global.asax file if not exist. Then, at the Application_Start event, add this line of code:

GlobalConfiguration.Configure(WebApiConfig.Register);

Service

Now, proceed to create a new controller that support Get, List, Create, Update and Delete function by using HttpGet, HttpPost, HttpPut and HttpDelete attributes like following code:

[RoutePrefix("api/AddressBook")]
public class AddressBookController : ApiController
{
    // GET api/<controller>
    [Route]
    [HttpGet]
    public List<AddressBook> Get()
    {
        AddressBookComponent bc = new AddressBookComponent();
        return bc.List();
    }

    // GET api/<controller>/5
    [Route("{id:int}")]
    [HttpGet]
    public AddressBook Get(int id)
    {
        AddressBookComponent bc = new AddressBookComponent();
        return bc.Get(id);
    }

    // POST api/<controller>
    [Route]
    [HttpPost]
    public void Create(AddressBook addressBook)
    {
        AddressBookComponent bc = new AddressBookComponent();
        bc.Create(addressBook);
    }

    // PUT api/<controller>/5
    [Route("{id:int}")]
    [HttpPut]
    public void Put(int id, AddressBook addressBook)
    {
        AddressBookComponent bc = new AddressBookComponent();
        bc.Update(addressBook);
    }

    // DELETE api/<controller>/5
    [Route("{id:int}")]
    [HttpDelete]
    public void Delete(int id)
    {
        AddressBookComponent bc = new AddressBookComponent();
        bc.Delete(id);
    }

}

[RoutePrefix("api/AddressBook")] attribute is used to create a template URL for your API. As the example above, the Web API URL is base at http://localhost:<port>/api/AddressBook

[Routeattribute is used to make an URL that base on the URL defined in RoutePrefix attribute which link to the particular method directly. For this case, I never specify any named parameter to the Route attribute, hence the URL to call this web function is the same, which is http://localhost:<port>/api/AddressBook. The incoming request will route to the correct function base on the supplied HTTP Verb.

[Route("{id:int}")] has specified named parameter. This attribute will route the request URL that contain parameter with integer type to that particular function. In this case, the URL that will hit that function is http://localhost:<port>/api/AddressBook/5

[Route("{id:int}")]
[HttpPut]
public void Put(int id, AddressBook addressBook)

Note that the above HTTP PUT method contain 2 parameters, one is the ID and another is the object. This is the standard PUT method declaration. If you have the method without the ID parameter, you will get HTTP 405 Method Not Allowed error because it will treat it as POST even you had specified HttpPut attribute.

Client

Now, start to create the client that will consume the above Web API. The Web API can only support JSON and XML HTTP content type, and I pick JSON for light weight payload and it is the commonly used format nowadays. We just need to make sure the HTTP request that sent to the Web API contain the content-type : application/json in the HTTP header. And to do that, I use HttpClient class which comes from the Microsoft ASP.NET Web API 2.2 Client Libraries. You can obtain it from NuGet:



In today's topic, I will also cover about how to use model binding in grid view (ASP.NET Web Form not MVC).

NOTE: Before you begin, I expect that you already had an entity or object which defined as a model.

Create a new ASP.NET web form project, then create a new page. Put a grid view in the page, then define the grid view like this:

<asp:GridView ID="addressBookGrid" runat="server"
    ItemType="AddressBookSample.Entities.AddressBook"
    SelectMethod="addressBookGrid_GetData"
    UpdateMethod="addressBookGrid_UpdateItem"
    DeleteMethod="addressBookGrid_DeleteItem"
    DataKeyNames="ID">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
    </Columns>
</asp:GridView>

First, put the model as the ItemType. Then, define the SelectMethod, UpdateMethod and DeleteMethod, when you do it, Visual Studio will automatically suggest, create and map the events for you. Put the model property name in the DataKeyNames which you think it is unique and can be an identifier for your object.

HTTP GET

The following is the implementation for the SelectMethod. It will send HTTP GET request to the Web API, then bind the responded data into the grid view automatically.

public IQueryable<AddressBook> addressBookGrid_GetData()
{
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:5593");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = client.GetAsync("api/AddressBook").Result;
    response.EnsureSuccessStatusCode();

    List<AddressBook> addressBooks = response.Content.ReadAsAsync<List<AddressBook>>().Result;

    return addressBooks.AsQueryable();

}

HTTP POST

The following is the implementation for a Create button. I have a form with text boxes and the Create button to let user enter the information that will be sent to the Web API.

protected void btnCreate_Click(object sender, EventArgs e)
{
    AddressBook addressBook = new AddressBook()
    {
        ID = Convert.ToInt32(createID.Text),
        FirstName = createFirstName.Text,
        LastName = createLastName.Text,
        Contact = createContact.Text
    };

    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:5593");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = client.PostAsync<AddressBook>("api/AddressBook", addressBook, new JsonMediaTypeFormatter()).Result;
    response.EnsureSuccessStatusCode();
}

HTTP PUT

The following is the implementation for the UpdateMethod. The method will automatically have the id parameter value which you had selected from the grid view, the code will send HTTP GET request to the Web API to retrieve the specific object first, then update the object, finally send the object with HTTP PUT request to the Web API.

public void addressBookGrid_UpdateItem(int id)
{
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:5593");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = client.GetAsync("api/AddressBook/" + id).Result;
    response.EnsureSuccessStatusCode();

    AddressBook item = response.Content.ReadAsAsync<AddressBook>().Result;

    // Load the item here, e.g. item = MyDataLayer.Find(id);
    if (item == null)
    {
        // The item wasn't found
        ModelState.AddModelError("", String.Format("Item with id {0} was not found", id));
        return;
    }
    TryUpdateModel(item);
    if (ModelState.IsValid)
    {
        // Save changes here, e.g. MyDataLayer.SaveChanges();
        HttpResponseMessage updateResponse = client.PutAsync<AddressBook>("api/AddressBook/" + id, item, new JsonMediaTypeFormatter()).Result;
        response.EnsureSuccessStatusCode();
    }

}

HTTP DELETE

The following is the DeleteMethod implementation. The method will also automatically have the ID parameter value which you had selected from the grid view, just simply send the ID with HTTP DELETE request to the Web API as follow:

public void addressBookGrid_DeleteItem(int id)
{
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:5593");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = client.DeleteAsync("api/AddressBook/" + id).Result;
    response.EnsureSuccessStatusCode();

}


That's it for a simple CRUD web application that deal with Web API. If you are interested with my source code, feel free to download it from HERE.




Monday, April 22, 2013

ASP.net WebAPI Weird Behavior

I have a simple WebAPI service with a method that accept and return single string parameter. The code look like this:


[HttpPost]
public string SubmitString(string input)
{
    return "Success";
}


Then, I use the following code to call my WebAPI:


using (HttpClient client = GetClientProxy())
{
    HttpResponseMessage response = client.PostAsync<string>("api/expense/SubmitString", input,
        new System.Net.Http.Formatting.JsonMediaTypeFormatter()
        ).Result;

    if (response.IsSuccessStatusCode)
    {
        // Parse the response body. Blocking!
        result = response.Content.ReadAsAsync<string>().Result;
    }
    else
    {
        // throw exception;
    }
}

It is weird that I keep getting HTTP404 error whenever I try to invoke the WebAPI method. Here is how my HTTP RAW content look like:


POST http://127.0.0.1:65000/api/expense/SubmitString HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: 127.0.0.1:65000
Content-Length: 6
Expect: 100-continue
Connection: Keep-Alive

"test"

After "googling" around, and found that WebAPI somehow not picking up simple value parameter automatically. I need to add [FromBody] attribute to the parameter, like this:


[HttpPost]
public string SubmitString([FromBody]string input)
{
    return "Success";
}

Yes, it works now. But, it behave differently when I create a WebAPI method which accept object parameter, I do not need to specify the [FromBody] attribute.

Also, note that WebAPI method only accept object type as parameter and the media formatter type are restricted to XML and JSON only.

In my previous post, I mentioned that the HttpClient.PostAsync<string> and HttpClient.PostAsync with StringContent are different. PostAsync<string> is posting whole string as an object, while the PostAsync with StringContent is posting HTTP RAW content.

What if I have the following WebAPI method which accept more than one parameter? Like this:


[HttpPost]
public string Submit2String(string input1, string input2)
{
    return "Success";
}


Unfortunately, it is not supported. The HTTP POST content can contain one object only. Therefore, we have to form an object that wrap both string objects into one object then only pass it to WebAPI method. WCF or web service developer like me would hate this kind of extra work and limitation. WCF has its built in SOAP serializer to parse the request packet and bind them correctly to the service method parameter a.k.a. the operation contract and data contract. However, the extra steps to wrap objects into one object before passing to WebAPI, somehow I feel it is similar to form SOAP envelope with wrapped objects. I only see one advantage of using WebAPI is the object (POX or JSON) passing via the wire is lightweight compare to SOAP.

Back to the problem, if you wish to accept more than one parameter in your WebAPI, you have to do the workaround like this:


[HttpPost]
public string Submit2String()
{
    string httpContent = this.Request.Content.ReadAsStringAsync().Result;
    string[] contents = httpContent.Split('&');

    Dictionary<string, string> parameterValue = new Dictionary<string, string>();
    foreach (string content in contents)
    {
        var temp = content.Split('=');
        parameterValue.Add(temp[0], temp[1]);
    }

    string input1 = parameterValue["input1"];
    string input2 = parameterValue["input2"];

    //Alternatively, if you hate the above string splitting code, you can have shortcut by using HttpUtility.ParseQueryString
    //Because the HTTP RAW content look like a query string anyway

    var option2 = HttpUtility.ParseQueryString(httpContent);

    string input_1 = option2["input1"];
    string input_2 = option2["input2"];

    return "Success";
}


Then, for your client, this is how you post your content:


using (HttpClient client = GetClientProxy())
{
    //Note: use content type application/x-www-form-urlencoded
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

    //Option 1:
    HttpResponseMessage option1 = client.PostAsync("api/expense/Submit2String",
        new StringContent("input1=" + input1 + "&input2=" + input2)
        ).Result;

    //Option 2:
    var content = new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("input1", input1),
            new KeyValuePair<string, string>("input2", input2)
        });

    HttpResponseMessage option2 = client.PostAsync("api/expense/Submit2String", content).Result;

}


As you can see, you have to post the content with FormUrlEncodedContent and specify the content type as "application/x-www-form-urlencoded". The HTTP content must be in this format: parameter1=value1&parameter2=value2&parameter3=value3. When the content has been posted to WebAPI method, you can manipulate or parse the content by splitting it with &, and then convert the value into any other object type you wish. Or, you can use HttpUtility.ParseQueryString to convert the content into NameValueCollection since the value format look like query string.

If you wish to post more than one parameter with object type, you can do the same workaround by posting the HTTP content with the serialized object XML or JSON string.


Send Transactional SMS with API

This post cover how to send transactional SMS using the Alibaba Cloud Short Message Service API. Transactional SMS usually come with One Tim...