' trying to make an web api controller with two parameters: one model object and string.
public string AddDevice(Device device, [FromBody] string userName)
{
// Some operations here
}
When I try it with one parameter on fiddler:
For Device object (body request):
{
"DeviceName":"name,
"StolenFlag":false
}
For string "[FromBody] string userName" (body request):
"userName"
It works fine. I just do not know how to make this method works with those two parameters. When I try connecting request body on fiddler like that:
{
"DeviceName":"name,
"StolenFlag":false
}
"userName"
I get an 500 error. It means, that server finds correct controller method but can't handle request. Any ideas?
First add the following line to WebApiConfig.cs in your App_Start folder.
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
It goes inside this function:
public static void Register(HttpConfiguration config)
Build your API and read the full error message from the Response. This should tell you exactly what's happening.
Since you can have only one parameter in the Request body you can change the method to accept username in the URI.
public string AddDevice([FromBody] Device device, string userName)
{
// Some operations here
return "";
}
Related
I have a GET end point which will take user name as parameter. Below is the action
[Route("user/{userName}")]
public User GetUserByName([FromUri] string userName)
{
// logic here
}
This is how i make the request.
var restClient = new RestClient("uri");
var request = new RestRequest("user/" + userName);
var response = restClient.Execute(request);
It worked fine for all cases till a user with name containing forward slash came.
Eg: Akbar/Badhusha
Then the request will looks like user/Akbar/Badhusha
This causing the request to return Not Fount error
I tried to add the parameter with AddQueryParameter method. All returning Not found error.
I also tried HttpUtility.UrlEncode
Also tried replacing / with %2f
Also tried user?userName=Akbar/Badhusha
All of them failed.
Is there any way to make it work?
Try removing [FromUri] from the parameter as shown below,
[Route("user")]
public User GetUserByName(string userName)
{
// logic here
}
And the request may look like,
user?userName=Akbar/Badhush
API post method is as show below,
[HttpPost]
public HttpResponseMessage CreateTemplate([FromUri]string templateName)
{
//Code...
}
and Angular post method is as show below,
CreateTemplate(templateName: string): Observable<any> {
return this.httpClient.post<any>(Url + "Templates/CreateTemplate?templateName=" + templateName, "");
}
How can I send the special characters to web API? If I try to send special characters, I will end up with receiving null in Web API.
The # indicates a fragment, it and everything after it doesn't get sent to the server.
Given you use it as a query string parameter, you need to percent-encode it:
templateName=" + encudeURIcomponent(templateName)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
I am getting an exception while reading the post data.
I get error on this line:
HttpContext.Current.Request.Form["UserID"].ToString();
And the error is :
System.Collections.Specialized.NameValueCollection.this[string].get
returned null.
In method I have put this code :
StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream);
string requestFromPost = reader.ReadToEnd();
and data comes in that properly like this:
{
"UserID": "1000",
"Password": "ABCD"
}
Why I am not getting value in this HttpContext.Current.Request.Form["UserID"].ToString()? I also tried Request.QueryString but no success here.
Where am I doing wrong? Any help or suggestion would be much appreciated. Thanks!
There is no Form on this request. For a request body to be interpreted as form data, it must:
have a content type of x-www-form-urlencoded
be actually formatted as form encoded values, i.e. UserID=foo&Password=bar
JSON content is JSON, it will not be interpreted as form-data.
Web API should already take care of this for you. Given an action method:
public void Action(Credentials credentials)
where the Credentials class looks something like:
public class Credentials
{
string UserID { get; set;}
string Password { get; set; }
}
You shouldn't have to do anything else to have the framework turn this incoming JSON data into an instance of Credentials and pass it to the action method. This is automatic unless you've done something strange that breaks the conventions that WebAPI expects.
I have been testing all the Get,Create,Update methods with Postman in which the Get passes in nothing. The Create and Update passes in raw json with Activity object with several properties that do match up with the C# class
So this signature for Create and Update works fine
[HttpPost]
public IHttpActionResult UpdateActivity(Activity activity)
Above works with Postman passing in JSON content type with all the properties. I have done this on OTHER projects.
HOWEVER
I'm trying to simply pass in a string and it is null no matter what
public IHttpActionResult DeleteActivity([FromBody]string Id)
{
// delete
var del = ActivityService.DeleteActivity(Id);
return Ok(del);
}
Postman I tried MANY ways
http://localhost:49810/api/activityapi/deleteactivity
I have tried MANY many ways based on blogs and google search one such example
{ "Id" = "5808786fa3e9ec79546b3c71" }
I know this is an older question but I wanted to help those who might have a similar problem as I was able to get this working.
In WebAPI Controller my method is setup as
[HttpPost]
public IHttpActionResult Create([FromBody] int eventId)
{
....
}
In order to get this to test properly in Postman you have to: In body, set to raw, make sure JSON (application/json) is set and then just add value like 2 that's it.. not like { "eventId":2 } which is proper JSON just the value and then it will work.
So in original poster's case, in Postman, if you set Body to raw, JSON (application/json) then "5808786fa3e9ec79546b3c71" as value it will work.
In Postman ensure the body is set to raw and select json and in the body just write "your string" in quotes. Do not use {} to surround it because that is to make a complex object
Try the following in the body, with the content-type as application/json
{ "5808786fa3e9ec79546b3c71" }
As when you specify it like so, it will attempt to de-serialize into a complex type with a property of Id
{ "Id" : "5808786fa3e9ec79546b3c71" }
Old question, but for those still wondering, I would recommend sending your string as a query parameter. Take a method like this for example:
[AllowAnonymous]
[HttpGet("resendEmailConfirmtionLink")]
public async Task<IActionResult> ResendEmailConfirmationLink(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null) return Unauthorized();
var origin = Request.Headers["origin"];
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
var verifyUrl = $"{origin}/verifyEmail?token={token}&email={user.Email}";
var message = $"<p>Please click the below link to verify your email address:</p><p><a href='{verifyUrl}'>Click to verify email</a></p>";
await _emailSender.SendEmailAsync(user.Email, "Please verify email", message);
return Ok("Email verification link resent");
}
This method expects a key value pair of a string called email. You can send your request like "http://localhost:5000/api/account/verifyEmail?email=myemail#test.com" or, in Postman, add it as a parameter like this:
postman query params
Your payload is not valid.
Change-->
{ "Id" = "5808786fa3e9ec79546b3c71" }
To-->
{ "Id" : "5808786fa3e9ec79546b3c71" }
[HttpPost]
public IHttpActionResult Create(int eventId)
{
....
}
Use form-data instead of raw-json
Key - eventId
Value - "5808786fa3e9ec79546b3c71"
This worked for me.
I have had a MobileService running on Azure, and have decided to create a new service and migrate the code myself. The new service is of the new type called: Azure Mobile App Service.
Currently I have Authentication working, and can do migrations/update-database. I am following the TodoItem example. I now want to create my own Custom API, which easily worked on MobileService, but I cannot get it working on Azure Mobile App :/
I have followed these two links web-Api-routing and app-service-mobile-backend. And I now have the following:
I have created a new controller:
[MobileAppController]
public class TestController : ApiController
{
// GET api/Test
[Route("api/Test/completeAll")]
[HttpPost]
public async Task<ihttpactionresult> completeAll(string info)
{
return Ok(info + info + info);
}
}
In the mobileApp.cs I have added the below code according to backend:
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
Additionally I have installed the below package according to web-api-routing:
Microsoft.AspNet.WebApi.WebHost
and the call from the client:
string t = await App.MobileService.InvokeApiAsync<string,string>("Test/completeAll", "hej");
Debug shows, that it is the correct URL:
{Method: POST, RequestUri: 'https://xxxxxxx.azurewebsites.net/api/Test/completeAll',
Version: 1.1, Content: System.Net.Http.StringContent, Headers:{ X-ZUMO-FEATURES:
AT X-ZUMO-INSTALLATION-ID: e9b359df-d15e-4119-a4ad-afe3031d8cd5 X-ZUMO-AUTH:
xxxxxxxxxxx Accept: application/json User-Agent:
ZUMO/2.0 User-Agent: (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=2.0.31125.0)
X-ZUMO-VERSION: ZUMO/2.0 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=2.0.31125.0)
ZUMO-API-VERSION: 2.0.0 Content-Type: application/json; charset=utf-8 Content-Length: 3}}
But keep getting: 404 (Not Found)
Debug Message "The request could not be completed. (Not Found)"
What am I missing :/ ?
Update
I have tried expanding the code in The mobileApp.cs, with:
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.UseDefaultConfiguration().MapApiControllers()
.ApplyTo(config);
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
based on app-service-backend, however still no access :/
Update
I used fiddler2 to access the endpoint through a browser and got the following results:
Update Again
I have tried to create another minimal solution, but still get the same error. Are there any great tutorials that I can follow to achieve this functionality?
The positive feeling is slowly evaporating . . .
The question is also running now on msdn, I will update here if any information is shown there.
Update
Tested Lindas comment, and I can in fact access the value converter:
// Use the MobileAppController attribute for each ApiController you want to use
// from your mobile clients
[MobileAppController]
public class ValuesController : ApiController
{
// GET api/values
public string Get()
{
MobileAppSettingsDictionary settings = this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter();
string host = settings.HostName ?? "localhost";
string greeting = "Hello from " + host;
traceWriter.Info(greeting);
return greeting;
}
// POST api/values
public string Post()
{
return "Hello World!";
}
}
This I access using the both the post and get function:
string t = await App.MobileService.InvokeApiAsync<string, string>("values", null, HttpMethod.Post, null);
or
string t = await App.MobileService.InvokeApiAsync<string, string>("values", null, HttpMethod.Get, null);
But the code I pasted has no route so why can I access it using values? What would the path be to the original controller if did not use the route parameter?
Extra Information
I have now created a support ticket with Microsoft and will update with additional information. . . Hopefully.
Update
Info from MSDN Forum: try MS_SkipVersionCheck
Reading about the attribute here, it does not seem applicable. But I tried it. Still Not Found for my API but the original one is still working. So it did not have an impact on this issue.
Yes !!!
So I finally got it working, I copied the usings from lidydonna - msft git and read about .net backend for mobileservice.
This ended with the following:
using System.Web.Http;
using Microsoft.Azure.Mobile.Server.Config;
using System.Threading.Tasks;
using System.Web.Http.Tracing;
using Microsoft.Azure.Mobile.Server;
namespace BCMobileAppService.Controllers
{
[MobileAppController]
public class TestController : ApiController
{
// GET api/Test
[HttpGet, Route("api/Test/completeAll")]
public string Get()
{
MobileAppSettingsDictionary settings = this.Configuration.GetMobileAppSettingsProvider().GetMobileAppSettings();
ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter();
string host = settings.HostName ?? "localhost";
string greeting = "Hello from " + host;
traceWriter.Info(greeting);
return greeting;
}
// POST api/values
[HttpPost, Route("api/Test/completeAll")]
public string Post(string hej)
{
string retVal = "Hello World!" + hej;
return retVal;
}
}
}
This is a new controller and not the one that comes with it as lidydonna used. It seemed like it wants both functions get and post. This resulted in the API was registered and could be accessed. This means the client call to the server I used was:
t = await App.MobileService.InvokeApiAsync<string, string>("Test/completeAll", null, HttpMethod.Post, new Dictionary<string, string>() { { "hej", " AWESOME !" }});
dialog = new MessageDialog(t);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
AND I GOT A RESPONSE YAY!!
Extra Information
The controllers that you create, i.e. the class needs to end with Controller, you can have text before but not after. This information was given on a MSDN forum discussion.
If the post and the get has the same input the server returns Not found. Having different inputs solves the issue.
In case of weird Internal Server Error, i.e. weird you can step through the entire server code all variables that you want to return are initialized, but the client receives the error. Then refer to Internal Server Error - Azure App Service Custom Controller where simple fix to the configuration can solve the issue.
You must have something wrong in your project configuration. I have a working sample here: https://gist.github.com/lindydonna/6fca7f689ee72ac9cd20
After creating the HttpConfiguration object, call config.MapHttpAttributeRoutes(). I added the route attribute [Route("api/Test/completeAll")] and I can confirm that the route is registered correctly.
Try adding this attribute to the ValuesController and check the route.
I found another cause for the 404 errors when it came to use attribute routing.
The code above originally had this in mobileApp.cs:
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.UseDefaultConfiguration().MapApiControllers()
.ApplyTo(config);
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
The config.MapHttpAttributeRoutes() needs to be moved above the .ApplyTo:
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
new MobileAppConfiguration()
.UseDefaultConfiguration().MapApiControllers()
.ApplyTo(config);
Try switching inheriting from ApiController to TableController.
It is really strange but simple API request is not working in azure app service
So I have figure out solution which has worked for me. I have tested http requests with c# http post/get, android post/get, and objective C post/get
So first of all you need to update your Startup.MobileApp.cs class :
new MobileAppConfiguration()
.UseDefaultConfiguration()
.MapApiControllers() /* /api endpoints **missing part***/
.ApplyTo(config);
Then create Azure Mobile App Custom Controller. After that modify little bit your controller to get proper json response
public class Mes
{
public string message { get; set; }
}
// GET api/My
public Mes Get()
{
return new Mes { message = "thanks" };
// return "Hello from custom controller!";
}
// POST api/My
public Mes Post(Mes chal)
{
return new Mes { message = chal.message + "asnwer" };
// return "Hello from custom controller!";
}
}
You can simple leave first variant and get response, but OBjective C will say to you that JSON text did not start with array or object and option to allow fragments...and so on.. This happens because you getting simple string not object. So that is why I have modified my response with class Mes
But it is also depends how you make request and what type of object you expect.
So .MapApiControllers() it is the main key for API and WEB API controller is now changed to azure custom controller.
Hope this helps.