MVC controller post entire model to remote api action - c#

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>();
}
}

Related

c# asp.net website calling a webApi

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");
}

Redirecting action from one controller to other with different secure attributes, ASP.NETCore 2.0

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.

Call MVC web API controller method from client

I am trying to consume/call an MVC Web API controller method, which will be used to upload a file. I am struggling to call it from my MVC controller.
Here's my code for the API Controller
public class ImportController : ApiController
{
[HttpPost]
public bool PutImportFile(byte[] fileToBeImported, string nameOfTheFileToBeImported)
{
// I am doing file saving stuff here
}
}
I have tested the file saving part by changing the method to HttpGet and its working when I called it directly from the browser. I removed the parameters for that.
However, I am not able to figure out how to call it from a client.
I have tried below.
public class ImportFileModel
{
public byte[] FileToBeImported { get; set; }
public string NameOfTheFileToBeImported { get; set; }
}
The below code will accept a file from the browser uploaded by user and post it to the API controller to save the file.
[HttpPost]
public async Task<JsonResult> Upload()
{
byte[] file;
string fileName = string.Empty;
if (Request.Files.Count > 0)
{
try
{
fileName = Request.Files[0].FileName;
using (MemoryStream ms = new MemoryStream())
{
Request.Files[0].InputStream.CopyTo(ms);
file = ms.ToArray();
}
//To do: get url from configuration
string url = "http://localhost:(port)/api/Import/PutImportFile";
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/bson"));
ImportFileModel request = new ImportFileModel
{
FileToBeImported = file,
NameOfTheFileToBeImported = fileName
};
MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
var result = await client.PostAsync(url, request, bsonFormatter);
HttpResponseMessage response = result.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
// exception handling here
}
}
return Json(true, JsonRequestBehavior.AllowGet);
}
It ends up in an exception at the last line.
HttpResponseMessage response = result.EnsureSuccessStatusCode();
Throwing 404 not found error.
I have also tried the same from a console application using HttpWebRequest. It also throws the same error.
Your Web API method PutImportFile is setup to receive two values, not a single model; hence, your HttpClient call is not recognized (no matching route found). Change your Web API method to receive a model:
public class ImportController : ApiController
{
[HttpPost]
public bool PutImportFile(ImportFileModel fileInfo)
{
//Your code to save the file...
}
}

Post from Console App to MVC Controller

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)

C# Calling WebApi method from MVC controller parameter is always null

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.

Categories