Accept x-www-form-urlencoded in Web API .NET Core - asp.net-core-2.0

I have a .NET Core Web API that is returning a 415 Unsupported Media Error when I try to post some data to it that includes some json. Here's part of what is returned in the Chrome Debugger:
Request URL:http://localhost:51608/api/trackAllInOne/set
Request Method:POST
Status Code:415 Unsupported Media Type
Accept:text/javascript, text/html, application/xml, text/xml, */*
Content-Type:application/x-www-form-urlencoded
action:finish
currentSco:CSharp-SSLA:__How_It_Works_SCO
data:{"status":"incomplete","score":""}
activityId:13
studentId:1
timestamp:1519864867900
I think this has to do with my controller not accepting application/x-www-form-urlencoded data - but I'm not sure. I've tried decorating my controler with Consumes but that does not seem to work.
[HttpPost]
[Route("api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromBody] PlayerPackage playerPackage)
{ etc..}
Any help greatly appreciated.
The following code worked fine in .NET 4.6.1 and I am able to capture and process the posts shown above.
[ResponseType(typeof(PlayerPackage))]
public async Task<IHttpActionResult> PostLearningRecord(PlayerPackage playerPackage)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var id = Convert.ToInt32(playerPackage.ActivityId);
var learningRecord = await _context.LearningRecords.FindAsync(id);
if (learningRecord == null)
return NotFound();
etc...

Try using [FromForm] instead of [FromBody].
public IActionResult Post([FromForm] PlayerPackage playerPackage)
FromBody > Bind from JSON
FromForm > Bind from Form parameters
You can also remove [FromBody] altogether and trial it then. Because you are expecting form-urlencoded should tell it to bind to object.

For PlayerPackage, the request should send a PlayerPackage Json Object, based on your description, you could not control the request which is posted from other place.
For the request, its type is application/x-www-form-urlencoded, it will send data with {"status":"incomplete","score":""} in string Format instead of Json object. If you want to accept {"status":"incomplete","score":""}, I suggest you change the method like below, and then convert the string to Object by Newtonsoft.Json
[HttpPost]
[Route("~/api/trackAllInOne/set")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm] string data)
{
PlayerPackage playerPackage = JsonConvert.DeserializeObject<PlayerPackage>(data);
return Json(data);
}

This did the trick for me:
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult Post([FromForm]IFormCollection value)

I had the same problem. FormDataCollection has no default constructors which is required by Formatters. Use IFormCollection instead.

Can make setting like as
[HttpPost()]/[HttpGet()]
[Consumes("application/x-www-form-urlencoded")]
public async Task<IActionResult> MethodName([FromForm] IFormCollection value)
don't forget to add [FromForm]

Related

Sending JSON String through http.post on REST API

I am having some trouble sending a JSON String through a http.post to the backend. I am working on a project that it already has its structure and everything.
I created a PaymentResource.java file acting as the REST controller for this functionality. I have also created a PaymentService. When calling from the TypeScript file I call like this
this.http.post(SERVER_API_URL + 'path/anotherpath',request);
This is my PaymentResource file
#RestController
#RequestMapping("/path")
public class PaymentResource {
private final Logger log = LoggerFactory.getLogger(PaymentResource.class);
public PaymentResource(){
}
#PostMapping("/anotherpath")
#ResponseStatus(value = HttpStatus.OK)
public void tokenize(#RequestBody String body) {
log.logger("here");
}
}
The string tokenize method never gets executed because I can not see the log.
Any help is appreciated it!
Thank you!
I figured it out. I was missing the subscribe on the component.ts:
this.paymentService.sendInfo().subscribe((response) => {
console.log(response.ok);
});
and an Observable on the service.ts file.

post parameter that passed in as #Field does not being added into RequestBody in Retrofit2?

base on Retrofit #Field doc, when making a post request
a combination of using #FormUrlEncoded and #Field will yields a request body of: paramName=paramValue&paramName=paramValue.
but what I am not getting field paramemters included in RequestBody.
my interface definition as below:
(I have no endpoint, and jake Wharton says use ./ as explicit intent that you want to use the path of the base URL and add nothing to it, but I tried #POST("./") it's not work, i got 404 not found error, so I add full url address to bypass this error temporarily)
public interface BannerService {
#FormUrlEncoded
#POST("http://10.10.20.190:6020/router")
Flowable<List<BannerBeanList.BannerBean>> getBannerData(#Field("method") String method, #Field("adspaceId") String adspaceId);
}
and this is how I make calls to interface service:
public class RemoteListDataSource implements RemoteDataSource {
#Override
public Flowable<List<BannerBeanList.BannerBean>> getBannerListData(ADFilterType adFilterType) {
BannerService bannerService = RetrofitHttpManger.getInstance().create(BannerService.class);
return bannerService.getBannerData("mz.app.ad.list", String.valueOf(adFilterType.getValue()));
}
}
below is retrofit instance in it's private constructor
retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//TODO baseurl tempororily hard code for test purpose
.baseUrl("http://10.10.20.190:6020/router/")
.build();
this is the result I got:
the current request body that I am logging is the common parameters that I added from FromBody in interceptor, only except the parameters that I passed in from #Field annoation, and server side info tells the same thing.
I have solved this issue, thanks to #iagreen's comment.
the request body was replaced by FormBody.Builder().add().build() which passed into chain.request().newBuilder().post().build() in my interceptor.
then the question turns out to be how to append paramemters in RequestBody, and the solution can refers to Retrofit2: Modifying request body in OkHttp Interceptor

Can't send volley post request from android phone

I'm using Volley to send an http post request with parameters from my android app to my local server running in http://192.168.1.4:3000/battery_signal_report
I'm pretty sure the server is running properly (I checked it with Postman successfully).
also, I successfully sent the request through Android Studio's Emulator using ip 10.0.2.2
Trying to make it work, i used various request implementations including JsonObjectRequest, StringRequest and the custom request described here: Volley JsonObjectRequest Post request not working
Also, I've read somewhere that Volley post requests have some problems with the request header, so i tried to override it in different ways.
Nothing works. onErrorResponse is called every time with an empty VolleyError input.
I've fairly new to android development, so any insights would be much appreciated.
Thanks in advance.
For anyone else coming across this, you need to forget about the header override and setup your own getBodyContentType() and getBody() methods. Follow this pattern:
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, successListener, errorListener) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";//set here instead
}
#Override
public byte[] getBody() {
try {
Map<String, String> params = yourObject.getMappedParams();
JSONObject json = new JSONObject(params);
String requestBody = json.toString();
return requestBody == null ? null : requestBody.getBytes("utf-8");
} catch (UnsupportedEncodingException uee) {
return null;
}
}
};

What's the equivalent of HttpContext.Current.User in an HttpListener-hosted service?

I've written a custom attribute for ServiceStack that has the following code in it:
public override void Execute(IHttpRequest request, IHttpResponse response, object requestDto) {
HttpContext.Current.User = GetUserFromOAuth2BearerToken(request);
}
This works beautifully when hosting in IIS, but when using the built-in HttpListener host, HttpContext.Current returns null.
What's the correct syntax to set, and get, the security principal associated with the current request/response when using HttpListener?
I am not sure the 'security principal/System.Security.Principal' is available with the current request/response when using AppHostHttpListenerBase.
You could pull get the User inforamation doing something like...
var sessionId = request.Cookies["ss-id"].ToString();
var user = request.GetCacheClient().Get<AuthUserSession>(sessionId);

How do I call my own service from a request/response filter in ServiceStack?

My problem is...
...I have a DTO like this
[Route("/route/to/dto/{Id}", "GET")]
public class Foo : IReturn<Bar>
{
public string Id { get; set; }
}
and need to call the service that implements the method with this signature
public Bar Get(Foo)
from a request and/or response filter. I don't know what class implements it (don't want to need to know). What I need is something like the LocalServiceClient class in the example below:
var client = new LocalServiceClient();
Bar bar = client.Get(new Foo());
Does this LocalServiceClient thing exists? JsonServiceClient has a pretty similar interface, but using it would be inneficient (I need to call my own service, I shouldn't need an extra round-trip, even to localhost, just to do this).
I'm aware of ResolveService method from Service class, but it requires me to have a service instance and to know what class will handle the request.
I think this LocalServiceClient is possible because I have all the data that a remote client (e.g. JsonServiceClient) needs to call the service - request DTO, route, verb - but couldn't find how to do it. Actually, it should be easier to implement than JsonServiceClient.
JsonServiceClient would do it, but there must be a better way, using the same request context.
What I want to do (skip this if you're not curious about why I'm doing this)
Actually, my DTOs are like this:
[EmbedRequestedLinks]
[Route("/route/to/dto/{Id}", "GET")]
public class MyResponseDto
{
public string Id { get; set; }
public EmbeddableLink<AResponseDto> RelatedResource { get; set; }
public EmbeddableLink<AnotherResponteDto> AnotherRelatedResource { get; set; }
}
EmbedRequestedLinksAttribute is a request/response filter. This filter checks if there is a query argument named "embed" in the request. If so, the filter need to "embed" the comma-separated related resources referenced by the argument into the response to this request. EmbeddableLink<T> instances can be obtained by using extension methods like these:
1) public static EmbeddableLink<T> ToEmbeddableLink<T>(this IReturn<T> requestDto)
2) public static EmbeddableLink<T> ToEmbeddableLink<T>(this T resource)
Assume a client places this request:
GET /route/to/dto/123456?embed=relatedResource HTTP/1.1
The service that will handle this request will return an instance of MyResponseDto with EmbeddableLinks created using signature (1). Then my response filter will see the embed query argument and will call the Get method of the appropriate service, replacing the RelatedResource with another instance of EmbeddableLink, this time created using extension method (2):
var client = new LocalServiceClient();
response.RelatedResource = client.Get(response.RelatedResource.RequestDto)
.ToEmbeddableLink();
The serialization routine of EmbeddableLink takes care of the rest.
In case an embeddable link is not included in the embed list the serialization routine will call the extension method ToUrl (provided by ServiceStack), that takes a verb and converts a request DTO into a URL. In this example the client will get this response:
{
"id": "9asc09dcd80a98",
"relatedResource": { "id": "ioijo0909801", ... },
"anotherRelatedResource":
{
"$link": { "href": "/route/to/another/dto/1sdf89879s" }
}
}
I know the creators of ServiceStack think that polymorphic request/responses are bad things but this case seems OK to me because I'm not creating services, instead I'm extending the framework to help me create services the way I (and possibly other users of ServiceStack) need. I'm also creating other hypermedia extensions to ServiceStack. (I hope my boss allow me to publish these extensions on github)
If you really want to do this then look the source code for ServiceStack. Look at the ServiceManager and ServiceController. These classes are responsible for registering and resolving services. You might even be able to use reflection to create services on the fly with the static EndpointHost.Metadata like so:
var operation = EndpointHost.Metadata.Operations
.FirstOrDefault(x => x.RequestType == typeof(Person));
if (operation != null)
{
var svc = Activator.CreateInstance(operation.ServiceType);
var method = operation.ServiceType.GetMethod("Get");
var response = method.Invoke(svc, new[] { new Person() });
}
This kinda works but you will get NULL exceptions if there is other code calling
var httpRequest = RequestContext.Get<IHttpRequest>();
But I would not suggest this.
Instead if you create your own Business Service classes that do all the CRUD operations (POST/PUT/GET ect). Then make the ServiceStack Services thin wrappers over them. Now you can call your own services whenever you want without worrying about the HTTP Request and ServiceStack. Only use the ServiceStack Service when you are dealing with HTTP requests
You can call the static AppHostBase.Resolve() method as demonstrated here, calling a SeviceStack Service from an MVC controller:
var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new HelloRequest { Name = User.Identity.Name });
However, I would take #kampsj's approach of making your ServiceStack services a thin wrapper around your application service classes and only deal with HTTP/Session specific stuff in the ServiceStack service.

Resources