Web API Routing changes after DB Refresh - asp.net-web-api

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.

Related

What is the difference between a Web application and 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);
}
}

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)
{
...
}

Instantiate new System.Web.Http.OData.Query.ODataQueryOptions in nunit test of ASP.NET Web API controller

I have an ASP.NET MVC4 Web API project with an ApiController-inheriting controller that accepts an ODataQueryOptions parameter as one of its inputs.
I am using NUnit and Moq to test the project, which allow me to setup canned responses from the relevant repository methods used by the ApiController. This works, as in:
[TestFixture]
public class ProjectControllerTests
{
[Test]
public async Task GetById()
{
var repo = new Mock<IManagementQuery>();
repo.Setup(a => a.GetProjectById(2)).Returns(Task.FromResult<Project>(new Project()
{
ProjectID = 2, ProjectName = "Test project", ProjectClient = 3
}));
var controller = new ProjectController(repo.Object);
var response = await controller.Get(2);
Assert.AreEqual(response.id, 2);
Assert.AreEqual(response.name, "Test project");
Assert.AreEqual(response.clientId, 3);
}
}
The challenge I have is that, to use this pattern, I need to pass in the relevant querystring parameters to the controller as well as the repository (this was actually my intent). However, in the case of ODataQueryOptions-accepting ApiController methods, even in the cases where I would like to use just the default parameters for ODataQueryOptions, I need to know how to instantiate one. This gets tricky:
ODataQueryOptions does not implement an interface, so I can't mock it directly.
The constructor requires an implementation of System.Web.Http.OData.ODataQueryContext, which requires an implementation of something implementing Microsoft.Data.Edm.IEdmModel, for which the documentation is scarce and Visual Studio 2012 Find References and View Call Hierarchy do not provide insight (what implements that interface?).
What do I need to do/Is there a better way of doing this?
Thanks.
Looks like someone else already answered this in the comments here, but it's not a complete solution for my use-case (see comment below):
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Customer>("Customers");
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request);
This is the solution I have been using in my NUnit tests to inject ODataQueryOptions
private static IEdmModel _model;
private static IEdmModel Model
{
get
{
if (_model == null)
{
var builder = new ODataConventionModelBuilder();
var baseType = typeof(MyDbContext);
var sets = baseType.GetProperties().Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>));
var entitySetMethod = builder.GetType().GetMethod("EntitySet");
foreach (var set in sets)
{
var genericMethod = entitySetMethod.MakeGenericMethod(set.PropertyType.GetGenericArguments());
genericMethod.Invoke(builder, new object[] { set.Name });
}
_model = builder.GetEdmModel();
}
return _model;
}
}
public static ODataQueryOptions<T> QueryOptions<T>(string query = null)
{
query = query ?? "";
var url = "http://localhost/Test?" + query;
var request = new HttpRequestMessage(HttpMethod.Get, url);
return new ODataQueryOptions<T>(new ODataQueryContext(Model, typeof(T)), request);
}

httpmessagehandler - reading content

I created a message handler which will log the request and the response. ideally I want to
public class LoggingMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LogRequest(request);
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
LogResponse(response);
return response;
});
}
private void LogRequest(HttpRequestMessage request)
{
var writer = request.GetConfiguration().Services.GetTraceWriter();
var content = request.Content;
(content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
{
writer.Trace(request, "request", System.Web.Http.Tracing.TraceLevel.Info, t =>
{
t.Message = x.Result;
});
});
}
private void LogResponse(HttpResponseMessage response)
{
var request = response.RequestMessage;
var writer = request.GetConfiguration().Services.GetTraceWriter();
var content = response.Content;
(content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
{
writer.Trace(request, "response", System.Web.Http.Tracing.TraceLevel.Info, t =>
{
t.Status = response.StatusCode;
t.Message = x.Result;
});
});
}
}
and here is my client code.
public ActionResult Index()
{
var profile = Client.GetAsync("Vendor").Result.EnsureSuccessStatusCode().Content.ReadAsAsync<VendorProfileModel>().Result;
return View(profile);
}
Logging appears to be working. However, when this handler is registered my client code returns an empty object. If I remove this handler the model is successfully read from the response and displayed on screen.
Is there a way to read the content and display the results on the client?
after a few more days for digging around on the net I finally found the root problem and a solution. First the problem:
everything in webapi is async
my action uses Controller.User which in turn is calling Thread.CurrentPrinciple
I am using ITraceWriter as my logging abstraction
apparently there is a bug in the ITraceWriter mechanicism where the current profile is not propagated across threads. therefore, i loose the principle when i get to my controller action. therefore, my query returns an empty result, rather than a fully populated result.
solution: don't use ITraceWriter to log messages. It would have been nice to use the built in mechanics, but that doesn't work. here is the link to the same issue which provides more detail/context.
https://aspnetwebstack.codeplex.com/workitem/237

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