I have a situation where I have an MVC Controller that I'm calling a WebApi POST method. I'm passing a DTO as a parameter... The WebApi method is hit, but the parameter is null. What am I missing?
Thanks!
MVC Controller:
[Authorize]
public async Task<ActionResult> Index()
{
Permissions service = new Permissions();
ViewBag.Title = "Deployment Manager";
string uri = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiRestfulUrl"] + "/Permissions";
using (var client = new HttpClient())
{
var permissions = new PermissionsDTO() { UserName = "rherhut" };
var response = await client.PostAsJsonAsync(uri, permissions);
if (response.IsSuccessStatusCode)
{
// Get response data how??
}
}
return View();
}
WebAPI POST Method:
public HttpResponseMessage Post(HttpRequestMessage request, [FromBody]PermissionsDTO permissions)
{
var data = repository.HasAdminRights(permissions.UserName); // permissions.UserName is null
var response = new ApiResponseCreator<PermissionsDTO>();
return response.FormatReturnData(request, data);
}
I resolved the problem by decorating the dto class with a "Serialize" attribute and for some reason this worked.
Related
I meet a problem because of my inexperience managing Threads.
I have this Action bellow :
public static async Task<joueurs> loadjoueurs(int id)
{
joueurs EmpInfo = new joueurs();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri("http://www.myWebApi.fr/api/");
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("joueurs?id=" + id);
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var EmpResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
EmpInfo = JsonConvert.DeserializeObject<joueurs>(EmpResponse);
return EmpInfo;
}
return null;
}
it s just client to get my data from a webApi (no ssl no authentication, when I test it I receive the right values)
but when I make a call using the function above (in my asp.net website) .... it stay stucked at the HttpResponseMessage = await .... eternally.
In my webApi I have two functions same name but different parameters .
public async Task<IHttpActionResult> Getjoueur(int iduser, int idsport)
and
public async Task<IHttpActionResult> Getjoueur(int id)
So I am don't know where the problem comes from.
(sequel) Here is the place where I call the Task :
public SuperModel(int id)
{
this.joueur = Repojoueurs.loadjoueurs(id).Result;
/* this.classificationSport = Repoclassificationsport.loadclassificationsport().Result;
...
*/
}
And then my Supermodel is instantiated here in my Home controller :
public ActionResult Index(int id)
{
SuperModel superModel = new SuperModel(id);
return View(superModel);
}
Can you try not to use the async and wait. Around three changes like below
public static HttpResponseMessage loadjoueurs(int id)
{
HttpResponseMessage Res = client.GetAsync("joueurs?id=" + id);
return Request.CreateResponse(HttpStatusCode.OK,EmpInfo, "application/json");
}
I have one question, which connected with redirecting and auth policies.
Let's have one controller, which allow Anonymous method like this:
[Route("Authorization")]
[Authorize]
public class AuthorizationController : Controller
{
...
[HttpPost]
[Route("AddUser")]
[AllowAnonymous]
public async Task<IActionResult> AddUser()
{
return await Task.Run<ActionResult>(() =>
{
return RedirectToAction("Post", "Proxy");
});
}
}
Second controller has Post method, which needs authorization
[Authorize]
public class ProxyController : Controller
{
...
[HttpPost]
public async Task Post()
{
var uri = new Uri(UriHelper.GetEncodedUrl(Request));
var routedUri = NewRouteBuilder(uri);
var client = new HttpClient();
var response = await client.PostAsync(routedUri, new StreamContent(Request.Body));
var content = await response.Content.ReadAsStringAsync();
Response.StatusCode = (int)response.StatusCode;
Response.ContentType = response.Content.Headers.ContentType?.ToString();
Response.ContentLength = response.Content.Headers.ContentLength;
await Response.WriteAsync(content);
}
}
If I use this code, I get 401 error in AuthorizationController, when I call AddUser.
Both these controllers are in one project. How it's possible to redirect on action in this case (which allow pass to action only authorized users or calls from ProxyController)?
Thank you.
I'm trying to perform a POST action to MVC controller like so:
string payload = "hello";
using (var httpClient = new HttpClient())
{
var str = new StringContent(new JavaScriptSerializer().Serialize(payload), Encoding.UTF8,
"application/json");
httpClient.BaseAddress = new Uri("http://localhost:52653/");
var response = httpClient.PostAsync("Home/TestPost", str).Result;
}
MVC Controller:
[HttpPost]
public ActionResult TestPost(string value)
{
var result = value;
return Content("hello");
}
When I debug I see the breakpoint hit in the controller but "value" param is null.
Is this even possible? can objects be sent this way as well? ie (Person)?
Try the FromBody attribute, that should work.
As #maccettura pointed out, you must include the proper namespace for this to work
using System.Web.Http;
[HttpPost]
public ActionResult TestPost([FromBody]string value)
{
var result = value;
return Content("hello");
}
Another method is this:
[HttpPost]
public async Task<string> TestPost(HttpRequestMessage request)
{
var requestString = await request.Content.ReadAsStringAsync();
return requestString;
}
You can use JsonConvert.SerializeObject() method.
var str = new StringContent(JsonConvert.SerializeObject(payload).ToString(), Encoding.UTF8,"application/json");
The serialized JSON string would look like:
{"payload":"hello"}
Also change
public ActionResult TestPost(string value)
TO
public ActionResult TestPost(string payload)
I have an API I would like to call from my front end MVC site. These two applications run on separate servers on the same network.
The API Controller has functions similar to:
[AllowCrossSiteJson]
public class VerifyMyModelController : ApiController
{
[HttpPost]
public MyResponse Post(MyModel model)
{
return MyHelper.VerifyMyModel(model);
}
[HttpPost]
public async Task<MyResponse> PostAsync(MyModel model)
{
return await MyHelper.VerifyMyModel(model);
}
// ... Gets below as well
}
Where MyHelper performs model verfication, DB lookups etc... and returns a common response object with response code, database id etc
My front end MVC site has a form the user fills out, this data gets posted to the local controller which I would like to forward on to the API. The API application is not accessible to the public, so I cannot post directly to it using AJAX etc. It must come from the sites controller.
I have tried the following but get a 500 internal server error as a response
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/", MyServer);
using (var c = new HttpClient())
{
var response = await c.PostAsJsonAsync(requestUri, json);
}
...
}
The var response contains the error message response 500.
I have also tried using a query string:
public string GetQueryString(object obj)
{
var properties = from p in obj.GetType().GetProperties()
where p.GetValue(obj, null) != null
select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());
return String.Join("&", properties.ToArray());
}
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
string queryString = GetQueryString(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/?{1}", MyServer, queryString);
using (var c = new HttpClient()){
var response = await c.GetAsync(requestUri); // API Also has GET methods
}
}
But the querystring method returns a 405 method not allowed response.
The MyModel is part of a shared class library with common models in it and is included in both applications.
Is there a better way of posting the entire model to the remote api action?
Thanks.
*Edit
RouteConfig of API:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
I added the following to the HomeController of the API's MVC site, to test it and I receive back the expected result, without error:
public async Task<ActionResult> TestVerifyMyModel(MyModel model)
{
var api = new VerifyMyModelController();
var res = await api.PostAsync(model);
return Json(res, JsonRequestBehavior.AllowGet);
}
So I know that the PostAsync Action of the controller works.. I just cant get it to work when called remotely.
I also enabled Failed Request Tracing on the server and have uploaded the generated XML file. It doesn't mean anything to me but thought it might help.
The posted route config looks more like your MVC route config than a Web Api one. But if it is the Web Api config, then shouldn't you be adding the ActionName to your url.
[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
var MyServer = ConfigurationManager.AppSettings["MyServer"];
var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);
var requestUri = string.Format(#"http://{0}/api/VerifyMyModel/PostAsync", MyServer);
using (var c = new HttpClient())
{
var response = await c.PostAsJsonAsync(requestUri, json);
}
...
}
Update: Sample code to retrieve Model from HttpClient response
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ConfigurationManager.AppSettings["MyServer"]);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/VerifyMyModel/PostAsync");
if (response.IsSuccessStatusCode)
{
var myResponseModel = await response.Content.ReadAsAsync<MyResponseModel>();
}
}
I'm trying to come up with a way to post to a Web API controller with one object but have a different, processed, object return. None of the methods I've been able to find have solved the issue.
Here's my method in my MVC project that posts to my Web API project
public dynamic PostStuff<X>(string action, X request)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var task = client.PostAsJsonAsync(new Uri("host/api/somecontroller/post, request);
task.Wait();
var response = task.Result;
return response;
}
}
This is my Web API controller code
public HttpResponseMessage Post([FromBody] FooObject foo)
{
var res = Request.CreateResponse(HttpStatusCode.OK,
new ValidationResponse<FooObject>
{
ID = new Random().Next(1000, 1000000),
Content =
new List<IContent>()
{
{
new Content()
{
Name = "TheContent",
Type = "SomeType",
Value = "This is some content for the page : " + foo.Bar
}
}
},
Product = new ProductFoo(),
Validated = true
});
return res;
}
}
When I put a break in my WebAPI controller code, the res variable is correctly created. Once the processing goes back to the PostStuff method, all I get is a StreamResponse with no trace of the ValidationResponse object created in the Web API controller. There are no errors but I can't use anything in the response beyond that the post succeeded. How can I extract the ValidationResponse from my posting method?
I have built myself this generic function as a helper for POSTing to Web API
Usage
var result = PostAsync<MyDataType, MyResultType>("http://...", MyData)
Function
public async Task<U> PostAsync<T, U>(string url, T model)
{
using (HttpClient httpClient = new HttpClient(httpHandler))
{
var result = await httpClient.PostAsJsonAsync<T>(url, model);
if (result.IsSuccessStatusCode == false)
{
string message = await result.Content.ReadAsStringAsync();
throw new Exception(message);
}
else
{
return await result.Content.ReadAsAsync<U>();
}
}
}
And HttpClientHandler configured for Windows Auth
protected HttpClientHandler httpHandler = new HttpClientHandler() { PreAuthenticate = true, UseDefaultCredentials = true };