Invoke POST method using Breeze not working - breeze

I am working on single page application using HotTowel. I have referred below link for invoking POST method using breeze.
http://www.breezejs.com/breeze-labs/breezeajaxpostjs
Below is my code.
On Server side:
public struct Customer {
public string CompanyName{ get; set; }
public string Phone { get; set; }
}
[HttpPost]
public IQueryable<Customer> SimilarCustomersPOST(Customer customer)
{
return repository.CustomersLikeThis(customer);
}
Invoking POST method using breeze.
var query = breeze.EntityQuery.from('SimilarCustomersPOST')
.withParameters({
$method: 'POST',
$encoding: 'JSON',
$data: { CompanyName: 'Hilo' , Phone: '808-234-5678' }
});
I am getting below error:
Error: The requested resource does not support http method 'GET'.
When I am writing a server code like below:
[System.Web.Http.AcceptVerbs("GET", "POST")]
[HttpPost]
public IQueryable<Customer> SimilarCustomersPOST(Customer customer)
{
return repository.CustomersLikeThis(customer);
}
It is invoking but accepted parameters getting null values.
Please let me know what is the reason I am getting this error.
Thanks in advance.

I'm not sure what happens when you mix [HttpPost] with [AcceptVerbs("GET")], but that might be the problem.
Note that in a GET method you need to use the [FromUri] attribute in front of parameters that are not simple value types, but you don't need that in a POST method. This blog post explains WebAPI parameter binding nicely.

Related

QueryString is always empty ASP.net Core 3.1

The query string I use is always empty. I have no idea why, and have tried for hours with
The HttpContext.Request returns all other parts of the URL except the querystring.
With this url https://localhost:44394/Trackers/Create?Place=Vision_College
and this Model
[BindProperties(SupportsGet = true)]
public partial class Tracker
{
[FromQuery(Name = "Place")] //populates it from the query
public string Place { get; set; }
...}
and this controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name, Phone, Place")] Tracker tracker)
{
OK I found an answer.
I was trying to use it in the POST of the CREATE, when I should have been using it in the GET part of CREATE
Thanks for everyones help!
Since you are using the query parameters in httpPost you should use, [FromQuery] inside your arguments. Follow this
Your DTO class would be,
public class Tracker
{
[FromQuery(Name = "Place")]
public string Place{ get; set; }
}
In your controller class
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([FromQuery]Tracker tracker)
{
}
Note: If your query parameters match with the model property names, specifically annotating the properties would not be necessary.
Better you can get by body itself since this is a post request. otherwise make this as a get request. If converting to get by body, simply use [FromBody] in endpoint arguments instead of [FromQquery]

ASP.NET Web API - How to Create Different Action Methods for Routes "product/id" and "product?someOtherId=10"

With Web API, I need to redirect the following two Restful routes to two different action methods:
/products/2 -> Get info for product id 2
/products?someOptionalId=456 -> Get info for all products. Use someOptionalId as a filter if provided.
Unfortunately using the standard routing and model binding scheme, since both URLs point to the same products controller and have one id as a parameter, I either run into a compile time issue creating two Get methods with same int parameter, or a run time issue with MVC not able to pick a particular action method
Compile time error
public IQueryable<Product> Get(int someOptionalIdQs)
{
}
public Product Get(int id)
{
}
Run time error (Note hack to use a string for someOptionalIdQs and then convert to int)
public IQueryable<Product> Get(string someOptionalIdQs)
{
}
public Product Get(int id)
{
}
Please suggest a fix ideally without having to make any routing config changes given that I would like to keep the routing as clean as possible. Thanks.
As your Method has an optional Id parameter you can simply use a nullable int for the Get for the collection.
The code below will support the following urls:
http:// server /api/products
http:// server /api/products?someOptionalIdQs=3
http:// server /api/products/2
Code example
public class Product
{
public string Name { get; set; }
}
public class ProductsController : ApiController
{
public IQueryable<Product> Get([FromUri] int? someOptionalIdQs = null)
{
if(someOptionalIdQs.HasValue)
{
//apply the filter
}
return new List<Product>().AsQueryable();
}
public Product Get(int id)
{
return new Product();
}
}
Use your first approach but try renaming one of your Get methods. Note that if the action name doesn't have a prefix of 'Get', make sure the [HttpGet] attribute is used.
// [HttpGet]
public IQueryable<Product> Get2(int someOptionalIdQs)
{
}
public Product Get(int id)
{
}
What you can do it probly see if the this.HttpContext.Request.QueryString.AllKeys.Contains("someOptionalIdQs") then do the processing according to Option Id Qs else your normal work flow would work.
But this would be a cryptic implementation an ideally you should create a new URL all together for a different work flow for the app.

MVC4 RC WebApi parameter binding

I upgraded from MVC4 beta to RC and the latest autofac. The following action was binding properly, but now both parameters are null. I see they changed things about the Formatters and such but I am not sure what caused my problem
[HttpPost]
RedirectModel MyAction(string value1, string value1)
REQUEST
Method: POST
Accept: application/json
URL: api/controller/myaction
BODY: {"value1":"1000", "value2":"foo"}
When you want to avoid using a DTO object, try this:
[HttpPost]
RedirectModel MyAction(dynamic value1, dynamic value2) {
string sValue1 = value1;
string sValue2 = value2;
Not really sure why the change from Beta, but I was able to make it work by changing the action signature to:
[HttpPost]
RedirectModel MyAction(MyActionDTO dto)
and defining MyActionDTO as
public class MyActionDTO
{
public string value1 { get; set; }
public string value2 { get; set; }
}
It was throwing an exception about not being able to bind to multiple body parameters using the two string paramaters. I guess using the DTO object more closely represents what you're sending in the AJAX call (a JSON object).

asp.net MVC 3 - reading POST payload in paramterized controller method

I had
[HttpPost]
public ActionResult Foo()
{
// read HTTP payload
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
The payload is application/json; worked fine; then I changed to
public ActionResult Foo(string thing)
{
....
}
The intention being to post to MyController/Foo?thing=yo
Now I cant read the payload(the length is correct but the stream is empty). My guess is that the controller plumbing has eaten the payload looking for form post data that can be mapped to the method parameters. Is there some way that I can stop this behavior (surely MVC should not have eaten a payload whose type is marked as JSON , it should only look at form post data). My work around is to add 'thing' to the json but I dont really like that
Try resetting the input stream position before reading:
public ActionResult Foo(string thing)
{
Request.InputStream.Position = 0;
var reqMemStream = new MemoryStream(HttpContext.Request.BinaryRead(HttpContext.Request.ContentLength));
....
}
Now this being said, if you are sending an application/json payload why on the holy Earth are you bothering to read directly the request stream instead of simply defining and using a view model:
public class MyViewModel
{
public string Thing { get; set; }
public string Foo { get; set; }
public string Bar { get; set; }
...
}
and then:
public ActionResult Foo(MyViewModel model)
{
// use the model here
....
}
ASP.NET MVC 3 has a built-in JsonValueProviderFactory which allows you to automatically bind JSON requests to models. And if you are using an older version it is trivially easy to add such factory your self as Phil Haack illustrates in his blog post.

WCF Web API - Model Binding to an object (Ensure that a request HttpOperationHandler has an output parameter with a type assignable to...)

On WCF Web API Preview 5, I am dealing with a strange behavior. Here is the scenario:
This is my model:
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
}
This is the API:
[ServiceContract]
public class PersonApi {
[WebGet(UriTemplate = "person?id={ID}&name={Name}&surname={Surname}&age={Age}")]
public Person Get(Person person) {
return person;
}
}
I registered the API with the following code:
RouteTable.Routes.MapServiceRoute<ADummy.PersonApi>("Dummy");
When I run try to reach the service with following URL, I get this error:
localhost:36973/Dummy/person?id=1&name=Tugberk&surname=Ugurlu&age=24
The service operation 'Get' will never receive a value for the input
parameter 'person' of type 'Person'. Ensure that a request
HttpOperationHandler has an output parameter with a type assignable to
'Person'.
But when I change my API logic like below it works:
[ServiceContract]
public class PersonApi {
[WebGet(UriTemplate = "person?id={ID}&name={Name}&surname={Surname}&age={Age}")]
public Person Get(int ID, string Name, string Surname, int Age) {
var p = new Person {
ID = ID,
Name = Name,
Surname = Surname,
Age = Age
};
return p;
}
}
In WCF Web API, I suppose things are not working like they work in ASP.NET MVC.
What is way of model binding to an object in WCF Web API?
UPDATE
I have added another method:
[WebInvoke(UriTemplate= "put", Method="POST")]
public Person Put(Person person) {
return person;
}
When I call this method with the following details:
Method: POST
URL: http://localhost:36973/Dummy/put
Accept:/ Content-Type:text/xml
Content-Length:189
BODY:
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>1</ID>
<Name>Tugberk</Name>
<Surname>Ugurlu</Surname>
<Age>25</Age>
</Person>
I get what I needed. So, query string binding to custom objects is not allowed?
Based on your experience, it appears that the design behavior is that Get() actions will only bind the parameters defined in your UriTemplate. In terms of purpose and security, this is the correct behavior.
With latest version of ASP.NET Web API (released with ASP.NET MVC 4 Beta) model binding is supported.
Model binding and validation: Model binders provide an easy way to extract data from various parts of an HTTP request and convert those message parts into .NET objects which can be used by the Web API actions.
With previous versions of ASP.NET Web API the desired functionality can be implemented with a HttpOperationHandler and in the OnHandle method return the model. Maybe the Validating model properties WCF Web APi question and answers can be used for inspiration.

Resources