What is the difference between a Web application and Web API? - asp.net-web-api

It sounds naive on hearing but how different are web application and Web API when someone mentions it in their paper?
How different are they from their functionalities?

Very short: web application, it's a web site, which you see in your browser, and web api, it's a service, which you use in a web application.
See also Difference between ASP.NET MVC and ASP.NET Web API:
Asp.Net MVC is used to create web applications that returns both views
and data but Asp.Net Web API is used to create full blown HTTP
services with easy and simple way that returns only data not view.

Web Applications are meant for their human interactions through views whereas Web API aka Web Services are meant for system-to-system interactions (information exchange programatically ). They exchange data.

Web Application:
It is an end-to-end solution for a user. Which means, User can:
Open it using a browser
Interact with it. He can click on something and after some processing, its result will be reflected in the browser screen. Human-System interaction
Web API
With Web APIs alone, a user can not interact with it, because it only returns data, not views.
It is a system which interacts with another system
It does not return views, it returns data
It has an endpoint set, which can be hit by other systems to get data which it provides.
Explanation using an ANALOGY
Web Application:
Suppose we have a cook. We can ask him to cook us anything, anytime!Suppose we ask our cook to cook us a burger. He'll process our request and will provide us a burger. ( This is like a Web Application; a complete solution. )
Web API
Now if we ask him to make us 'McDonalds' burger, can he cook and bring us that? No!
Here comes the concept of APIs! (for this example, lets suppose McDonalds only give takeaways to cooks only)
McDonalds-Takeaways is like an API. Which allows other systems (cooks) to hit it and bring back desired data. So we can ask our solution (our cook) to
go to McDonalds Takeaway
Buy the burger and bring us that
So what happened is, we asked our "System" to talk to this McDonalds-takeaways (API System) and bring back the result we desired.

Web app is a website that is running in your browser and web Api is service

Web API is back-end application(server side) where actual functionality to call service/database call is happening to store and retrieve the data.
Web Application is front end application(client side)which is calling web API to present the data retrieved from back-end.
eg: To check the account balance in your mobile banking app, you are able to see your account details in front end. But all the calculations of interest /balance is happening in the back end.

In simplest word, a web application's response to requests are html, css, javascript and anything that a browser can render (graphical), whereas a web api returns non-graphical "data". Having said that, I think we can make a web api work like a web application because html is still data.

Create :
public IHttpActionResult GetAllProduct()
{
IList<product> pro = null;
using (var ctx = new TestMVCEntities())
{
pro = ctx.products.ToList();
}
if (pro.Count == 0)
{
return NotFound();
}
return Ok(pro);
}
public IHttpActionResult PostNewProduct(product pro)
{
using (var ctx = new TestMVCEntities())
{
ctx.InUPProduct(pro.pid,pro.pname,pro.pprice);
ctx.SaveChanges();
}
return Ok();
}
public IHttpActionResult PutOldProduct(product pro)
{
using (var ctx = new TestMVCEntities())
{
product c = (from x in ctx.products
where x.pid == pro.pid
select x).First();
if (c != null)
{
c.pname = pro.pname;
c.pprice = pro.pprice;
ctx.SaveChanges();
}
else
{
return NotFound();
}
}
return Ok();
}
public IHttpActionResult Delete(int id)
{
using (var ctx = new TestMVCEntities())
{
var pro = ctx.products
.Where(s => s.pid == id)
.FirstOrDefault();
ctx.Entry(pro).State = System.Data.Entity.EntityState.Deleted;
ctx.SaveChanges();
}
return Ok();
}
Consume :
public JsonResult GetProductsData()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44350/api/");
//HTTP GET
var responseTask = client.GetAsync("product");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<product>>();
readTask.Wait();
var alldata = readTask.Result;
var rsproduct = from x in alldata
select new[]
{
Convert.ToString(x.pid),
Convert.ToString(x.pname),
Convert.ToString(x.pprice),
Convert.ToString(x.pimage),
Convert.ToString(x.pisdemand),
Convert.ToString(x.pcname),
Convert.ToString(x.psupply)
};
return Json(new
{
aaData = rsproduct
},
JsonRequestBehavior.AllowGet);
}
else //web api sent error response
{
var pro = Enumerable.Empty<product>();
return Json(new
{
aaData = pro
},
JsonRequestBehavior.AllowGet);
}
}
}
public JsonResult InupProduct(string id,string pname, string pprice)
{
try
{
product obj = new product
{
pid = Convert.ToInt32(id),
pname = pname,
pprice = Convert.ToDecimal(pprice)
};
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44350/api/product");
//HTTP POST
var postTask = client.PostAsJsonAsync<product>("product", obj);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
return Json(1, JsonRequestBehavior.AllowGet);
}
else
{
return Json(0, JsonRequestBehavior.AllowGet);
}
}
/*context.InUPProduct(Convert.ToInt32(id),pname,Convert.ToDecimal(pprice));
return Json(1, JsonRequestBehavior.AllowGet);*/
}
catch (Exception ex)
{
return Json(0, JsonRequestBehavior.AllowGet);
}
}
public JsonResult deleteRecord(int ID)
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44350/api/product");
//HTTP DELETE
var deleteTask = client.DeleteAsync("product/" + ID);
deleteTask.Wait();
var result = deleteTask.Result;
if (result.IsSuccessStatusCode)
{
return Json(1, JsonRequestBehavior.AllowGet);
}
else
{
return Json(0, JsonRequestBehavior.AllowGet);
}
}
/* var data = context.products.Where(x => x.pid == ID).FirstOrDefault();
context.products.Remove(data);
context.SaveChanges();
return Json(1, JsonRequestBehavior.AllowGet);*/
}
catch (Exception ex)
{
return Json(0, JsonRequestBehavior.AllowGet);
}
}

Related

Custom Async Action Filter for Web API 2

I have a web api to consume the data coming from android mobile. This web api will consume the multi part file from along with the form data the web api request. I followed this article to archive.
[CustAuthAsync]
public async Task<HttpResponseMessage> SaveEHSInspectionData()
{
try
{
string root = HttpContext.Current.Server.MapPath("~/App_Data");
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(root);
//do stuff
var res = await Request.Content.ReadAsMultipartAsync(provider);
// DO SOME STUFF
}
catch (Exception exp)
{
}
return Request.CreateResponse(HttpStatusCode.OK, result);
}
I wanted to do the custom access validation for this web api, so implemented a filter to validate the request.
I have the filter like below
public class CustAuthAsyncAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
InternalOnExecutingAsync(actionContext);
}
}
The internal method like this
protected void InternalOnExecutingAsync(HttpActionContext actionContext)
{
var authValue = actionContext.Request.Headers;
if (authValue.Contains("CustomAccessToken"))
{
string token = authValue.GetValues("CustomAccessToken").First();
var result = // doing some decription
if (result != null)
{
bool validationResult = // validation with database
if (!validationResult)
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Invalid token" };
}
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Invalid token" };
}
}
else
{
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{ ReasonPhrase = "Unauthorized Request" };
}
These implementations are working fine in API Client Tools (Example: Postman) if the validation passes, allows the request to the method.
Postman Response screen shot
This is not working in mobile app, Saying the response message as Unauthorized Access. and not allowing the request to the method even the custom access validations are passed.
FYI : This method is working fine in mobile without filter
Help me to get this works in mobile app also.
Thanks in advance.
Your using the wrong type of filter to manage access. You should use an authorization filter. Besides you can't have an async method to authorize. You have to make the calling client wait for clearance. This may cause the side effects you're experiencing.
I'm not sure this has any to do with fact that it's a mobile application, however the authorization phase ir prior to the processing of the request. Verify that your are not using any other form of authorization in your project.
You should implement an authorization filter by inheriting AuthorizeAttribute and overriding IsAuthorized(HttpActionContext actionContext) method:
public class CustAuthAsync : AuthorizeAttribute
{
public CustAuthAsync()
{
///Some initialization if required. Otherwise, not necessary to declare the constructor..
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
var authValue = actionContext.Request.Headers;
if (authValue.Contains("CustomAccessToken"))
{
string token = authValue.GetValues("CustomAccessToken").First();
var result = // doing some decription
if (result != null)
{
return //database validation
}
else
{
return false;
//No need to create special unauthorized response. You should not hint the reason at this point. You can do this in the HandleUnauthorizedRequest method.
}
}
else
{
return false;//No need to create special unauthorized response.
}
}
}
You can use this attribute to decorate your controllers. You can even pass parameter in the constructor for more granular control on access management, like a required role to access de controller.

Web API Routing changes after DB Refresh

This is an exceedingly strange problem and I'm only including it as an oddity in case someone's seen it before.
I am on C#, ASP.Net web api, Fluent Nhibernate and SQL Server 2012
I have a Meal object that I pass to a web api controller method :
[HttpPost]
[ActionName("PostMeal")]
public HttpResponseMessage PostMeal(Meal mealToPost)
{
var helper = new Datahelper();
try
{
var fshelper = new FoodServiceHelper(helper);
fshelper.SaveMeal(mealToPost);
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
var response = Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, ex);
return response;
}
}
The method that posts is similarly very simple:
public void SaveMeal(Meal mealToPost)
{
var url = _connectionString + "food/PostMeal";
var client = new HttpClient();
var formatter = new JsonMediaTypeFormatter
{
SerializerSettings = { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }
};
var clientTask = client.PostAsync(url, mealToPost, formatter)
.ContinueWith(posttask => posttask.Result.EnsureSuccessStatusCode());
clientTask.wait();
}
The meal object is pretty straightforward. Some elementaries, some generic collections.
I am able to post normally for several (usually about 20) meals, at which point it is somehow no longer able to find the route. I verified this by adding breakpoints to the server side. It hits it the first several times, then it won't even find the controller method.
Here's the weird part. If I drop and recreate the database, it's ok again for another 20 or so meals.
I suspect that this is some kind of mapping issue, but I cannot prove it.
Curious.

How do you read POST data in an ASP.Net MVC 3 Web API 2.1 controller?

This does not seem to be as easy as I thought. I found some solutions on the web, but they are not working for me. I have an ASP.Net MVC 3 project with the Microsoft ASP.Net Web API 2.1 nuget package installed. Now, I want to be able to read data posted to a web api controller. The data sent will vary, so I cannot used a strongly typed ViewModel.
Here are the solutions I tried:
public void Post([FromBody]string value)
{
...
}
public void Post([FromBody]List<string> values)
{
...
}
public void Post([FromBody]NameValueCollection values)
{
...
}
But my value or values variables are always empty. I know the controller is receiving data however because I can check it by accessing (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"].Request.Form. It does not look like the proper way to retrieve the data though. There ought to be a cleaner way.
UPDATE:
Here is how I am posting the information:
I am posting the data from another controller in the same web application:
public ActionResult SendEmailUsingService()
{
dynamic email = new ExpandoObject();
email.ViewName = "EmailTest";
email.From = "fromaddress#yahoo.com";
email.To = "toaddress#gmail.com";
email.Fullname = "John Smith";
email.Url = "www.mysite.com";
IDictionary<string, object> data = email;
using (var wb = new WebClient())
{
string url = BaseUrlNoTrailingSlash + Url.RouteUrl("DefaultApi", new { httproute = "", controller = "Emailer" });
var response = wb.UploadValues(url, "POST", data.ToNameValueCollection());
}
return View();
}
And here is what I am getting in my Post web api controller if I declare an httpContext variable like this:
var httpContext = (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"];
httpContext.Request.Form =
{ViewName=EmailTest&From=fromaddress%40yahoo.com&To=toaddress%40gmail.com&Fullname=John+Smith&Url=www.mysite.com}
httpContext.Request.Form is a System.Collections.Specialized.NameValueCollection {System.Web.HttpValueCollection}
I finally found the answer to my question here:
Web API Form Data Collection
The solution is to use FormDataCollection:
public void Post([FromBody]FormDataCollection formData)
{
...
}

How to create roles and add users to roles in ASP.NET MVC Web API

I have a .NET Web API project that users the individual accounts. I can register users fine using the standard template AccountController. However, I now want to set up roles and add users to roles depending on the type of user.
There are no roles automatically set up in the DB. How do I set up the roles and how do I add users to the roles?
The only information I can find on this is based on the old ASP.NET Membership, so it fails on the fact that the stored procedures are not set up for it.
Have scoured forums and tutorials on MSDN and can't seem to find an example for Web API.
You can add roles using the RoleManager...
using (var context = new ApplicationDbContext())
{
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
await roleManager.CreateAsync(new IdentityRole { Name = "Administrator" });
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user = new ApplicationUser { UserName = "admin" };
await userManager.CreateAsync(user);
await userManager.AddToRoleAsync(user.Id, "Administrator");
}
You're right that documentation is a bit light right now. But I find that once you've worked with the RoleManager and the UserManager a bit, the API's are pretty discoverable (but perhaps not always intuitive and sometimes you have to run queries directly against the store or even the db context).
It took me awhile to figure out but I finally got it. Anthony please excuse me but going to repost a lot of your code so that dumb developers like me can understand.
In the latest WebAPI2 (Visual Studio 2013 Update 2) the registration method will look like so:
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
What you want to do is replace it with this:
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
using (var context = new ApplicationDbContext())
{
var roleStore = new RoleStore<IdentityRole>(context);
var roleManager = new RoleManager<IdentityRole>(roleStore);
await roleManager.CreateAsync(new IdentityRole() { Name = "Admin" });
var userStore = new UserStore<ApplicationUser>(context);
var userManager = new UserManager<ApplicationUser>(userStore);
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
result = await UserManager.CreateAsync(user, model.Password);
await userManager.AddToRoleAsync(user.Id, "Admin");
}
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
Now when you post it should correctly work, but you may run into a further problem. After I did this my response complained about the DB.
The model backing the <Database> context has changed since the database was created
To fix this error I had to go into the Package Manager Console and enable Migrations.
Enable-Migrations –EnableAutomaticMigrations
Then:
Add Migration
Finally:
Update-Database
A good post on enabling migrations here:
http://msdn.microsoft.com/en-us/data/jj554735.aspx

Ajax.ActionLink failing

Right now I'm learning about MVC's implementation of Ajax and I'm having trouble getting it to work correctly. Here's what I have:
#Ajax.ActionLink("Click here to get a title", "Yo",
new AjaxOptions { OnSuccess = "alert(\"YES!\")", OnFailure = "alert(\"WHY?!\")" })
And here are the two controller methods:
public PartialViewResult GetThatTitle()
{
var titular = new TitleDataEntity { };
titular.TitleName = "Inception!";
titular.PublishDate = DateTime.Now;
titular.Id = 2;
return PartialView("_testView", titular);
}
public JsonResult Yo()
{
var titular = new TitleDataEntity { };
titular.TitleName = "Inception!";
titular.PublishDate = DateTime.Now;
titular.Id = 2;
if(Request.IsAjaxRequest())
{
return Json(titular);
}
return Json(titular);
}
When I call the function "Yo", the browser gives me the "WHY?!" alert box. But when I call GetThatTitle, it gives me the success alert. Why is it failing when I try and return a Json result?
You need to allow GET requests like this when returning JSON which are disabled by default:
return Json(titular, JsonRequestBehavior.AllowGet);
Also I would strongly recommend you using FireBug. It shows all AJAX requests in its console and you see the requests and responses. If you have used it you would have seen the following:
InvalidOperationException: This
request has been blocked because
sensitive information could be
disclosed to third party web sites
when this is used in a GET request. To
allow GET requests, set
JsonRequestBehavior to AllowGet.]
which would have put you on the right track of course.

Resources