I have an MVC project that is exposed externally. I have an internal Web API project.
For reasons beyond my control, I cannot expose the Web API project directly and I cannot add Web API Controllers to my MVC project.
I need to create an MVC Controller that will act as a proxy for a Web API Controller. I need the response from the MVC Controller to look as if the Web API was called directly.
What is the best way to accomplish this?
Is there a better approach than what I have so far?
How can I fix the error that I am getting?
Here is what I have so far:
MyMVCController
[HttpGet]
public HttpResponseMessage GetData(HttpRequestMessage request)
{
...
var response = proxy.GetData();
return request.CreateResponse();
}
MyProxyClass
public HttpResponseMessage GetData()
{
...
return HttpRequest(new HttpRequestMessage(HttpMethod.Get, uri));
}
private HttpResponseMessage HttpRequest(HttpRequestMessage message)
{
HttpResponseMessage response;
...
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(120);
response = client.SendAsync(message).Result;
}
return response;
}
In the MVC Controller, I am getting an InvalidOperationException on the request.CreateResponse() line. The error says:
The request does not have an associated configuration object or the provided configuration was null.
Any help would be greatly appreciated. I have searched Google and StackOverflow but I haven't been able to find a good solution for creating this proxy between MVC and Web API.
Thanks!
You can do it by just creating some JsonResult action in your controller which will return result of calling web API.
public class HomeController : Controller
{
public async Task<JsonResult> CallToWebApi()
{
return this.Content(
await new WebApiCaller().GetObjectsAsync(),
"application/json"
);
}
}
public class WebApiCaller
{
readonly string uri = "your url";
public async Task<string> GetObjectsAsync()
{
using (HttpClient httpClient = new HttpClient())
{
return await httpClient.GetStringAsync(uri);
}
}
}
Related
I am working on an api that allows managment of contacts.
I've generated my Entity Framework Context, Models, and Controllers.
My Api request are made in a Proxy class (called APIHelper) that contains methods to be used in my app.
My API has no problem returning results when calling the Get methods to fetch my list of Contacts, but when sending a PUT or POST request.
These Request actually work, the Instructions contained within each Method are executed correctly, PUT modifies my Contacts, POST creates a new Contacts, but reaching the end of either methods, right after it returns, the Program stops, or at least it looks like it.
There are no feedbacks from either the API which looks like it did its job, and the Proxy class which still seems to be awaiting the response from the API.
Here is the code doing the Request from the Proxy APIHandler Class :
public static async Task<bool> PostEdiContact(EdiContact ediContact)
{
string query = $"{ApiPred}/api/EdiContacts";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(query);
//HTTP POST
var result = await client.PostAsJsonAsync(query, ediContact);
return result.IsSuccessStatusCode;
}
}
Here is the code From the controller :
[ResponseType(typeof(EdiContact))]
public async Task<IHttpActionResult> PostEdiContact(EdiContact ediContact)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.EdiContacts.Add(ediContact);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateException e)
{
if (EdiContactExists(ediContact.contactID))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = ediContact.contactID }, ediContact);
}
This last return is where the next execution just seems to go into the beyond as I have no clue about where it goes next. It works the fine for the Get Methods, but not these.
I have found no similar cases online and no one around me can help me with it.
As an additional ressources, here is the WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config
.Formatters
.JsonFormatter
.SerializerSettings
.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
// Removing Xml formatter
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
}
Testing the request using swagger also returns an a response with code 201 so everything seems fine. but my Proxy Class doesn't get anything awaiting the response.
So I couldn't get it to work by using the PostAsJsonAsync() method from the HttpClient class.
What I did to work around this issue is using the basic SendAsync() method.
It is a bit more work since you need to declare and initialise an HttpRequestMessage, but here is what it looks like :
public static async Task<bool> PostEdiContact(EdiContact ediContact)
{
string json = JsonConvert.SerializeObject(ediContact);
using (HttpClient client = new HttpClient())
{
string url = $"{ApiPred}/api/EdiContact";
using(HttpRequestMessage request = new
HttpRequestMessage(HttpMethod.Post, url))
{
StringContent stringContent = new StringContent(
json,
Encoding.UTF8,
"application/json");
request.Content = stringContent;
HttpResponseMessage response = await client.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
throw new Exception("An error occured");
response.EnsureSuccessStatusCode();
return true;
}
}
}
I have two solutions one is an MVC5 web app and the other is an MVC core 2.2 web app that acts as a basic web form.
I am trying to post the webform data (using a ViewModel) to the MVC5 web app API.
The Code
The POST method on the MVC5 web app/api
// POST
[HttpPost]
public IHttpActionResult Post([FromBody] WebFormDataVM personData)
{
// logic here
}
The MVC core webform (posting to the above)
[HttpPost]
public async Task<ActionResult> Create(PersonVM personData)
{
var path = "api/WebForm/Post";
var url = new Uri("http://localhost:60291/");
var client = new HttpClient();
client.BaseAddress = url;
var response = await client.PostAsJsonAsync(path, personData);
return RedirectToAction("Index");
}
The Issue
When posting the viewmodel the POST method API parameter (WebformDataVM personData) is always null.
I have tried the exact same setup but using an MVC5 project/solution instead of core and it works without fail.
What i have tried
Posting a string instead of view model object
Removing HTTPS from the .net core project (via the project options)
Any help would be greatly appreciated.
you should srialize your object to json
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var url ="yourUrl" // http://localhost:60291/api/WebForm/Post
var model=yourObject; //PersonVM
HttpResponseMessage response = await client.PostAsync(url, new StringContent(JsonConvert.SerializeObject(yourObject),Encoding.UTF8, "application/json"));
}
Please try with this solution
[HttpPost]
public async Task<ActionResult> Create(PersonVM personData)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:60291/api/WebForm/Post");
var response = await client.PostAsJsonAsync("personData", personData);
return RedirectToAction("Index");
}
}
[HttpPost]
public IHttpActionResult Post(WebFormDataVM personData)
{
// code
}
I have to retrieve orders from my API made in NET Core.
The retrieval is made in an action of my MVC controller calling an endpoint of another NET Core APP using GET.
The API endpoint is the following one:
API:
[HttpGet("orders/orderSearchParameters")]
public IActionResult Get(OrderSearchParameters orderSearchParameters)
{
var orders = MenuService.GetMenuOrders(new GetMenuOrdersRequest { From = orderSearchParameters.From, To = orderSearchParameters.To, FoodProviderId = orderSearchParameters.FoodProviderId }).Orders;
return Ok(orders);
}
An action of my Web App MVC controller must call that endpoint, and for that this is the following code:
public IActionResult GetOrders(OrderSearchParametersModel orderSearchParameters)
{
var uri = string.Format(ApiUri + "menus/orders/");
using (HttpClient httpClient = new HttpClient())
{
var response = httpClient.GetStringAsync(uri);
if (response.IsCompleted)
{
var orders = JsonConvert.DeserializeObject<List<OrderModel>>(response.Result);
return Ok(orders);
}
else
{
return BadRequest();
}
}
}
What I canĀ“t find is how can I serialize OrderSearchParametersModel to perform the GET operation with the HttpClient in the MVC controller.
In the attached code I do the GET without the incoming object.
How can I send this object using GET operation with HttpClient?
If you put all your parameters in the querystring, they will be translated into an OrderSearchParametersModel but they need to match this model properties names.
Under one colution file I have couple of projects.UI (ASP.Net mvc) project, A project for my rest services, A DTO project, A business logic project and Data Access. Now my services projects's controller needs to talk with my UI(ASP.Net MVC) project's controller and get the data entered in the form and send it to the database. Im quite unsure of the logic I should come up with inside the controller class of the UI project. The UI project sepratley has entity classes as well. Help needed!!
This is the POST method in my services controller
// POST api/Maintenance
[HttpPost]
public IHttpActionResult Post([FromBody]Maintenance maintenance)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
maintenanceLogic.Insert(maintenance);
return CreatedAtRoute("DefaultApi", new { id = maintenance.WorkID }, maintenance);
}
This is the method that will access the above methods uri.This method is in the controller class of my UI project. I came up with a logic.But I think its not correct.
[HttpPost, Route("/maintenance/CreateMaintenanceOrder")]
public PartialViewResult CreateMaintenanceOrder([FromBody] Maintenance Model)
{
Model.CheckItems = maintenanceViewModel.CheckItems;
Model.CrewMembers = maintenanceViewModel.CrewMembers;
Model.WorkID = ++SessionUtility.CurrentMaintenanceID;
try
{
var uri = "api/Maintenance/Post ";
using (HttpClient httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("http://localhost:8961");
Task<String> request = httpClient.GetStringAsync(uri);
Model = JsonConvert.DeserializeObject<List<Maintenance>>(request.Result);
}
maintenanceViewModel.MaintenanceOrders.Add(Model);
}
catch (AggregateException e)
{
}
maintenanceViewModel.MaintenanceOrders.Add(Model);
return PartialView("_Search", maintenanceViewModel);
}
You are trying to call a Post method using GetAsync as well as it seems you are not passing the Maintenance object required by Rest service method as input. Please try below -
string maintenanceData = JsonConvert.SerializeObject(Model); //considering you have to pass Model as input to Rest method
HttpResponseMessage response = httpClient.PostAsync(new Uri("http://localhost:8961" + "api/Maintenance/Post/"), new StringContent(maintenanceData));
Im a beginner with Web api and Im trying to setup a simple owin selfhosted service that Im trying out.
I've been searching stackoverflow and other places for a while now, but I cant seem to find anything obviously wrong.
The problem I have is that I get a bad request response everytime I try to call my service.
The controller looks like this:
[RoutePrefix("api/ndtdocument")]
public class NDTDocumentsController : ApiController, INDTDocumentsController
{
[HttpGet]
public IHttpActionResult Get()
{
var document = Program.NDTServerSession.GetNextNDTDocument(DateTime.Today);
if (document == null)
return null;
return Ok(document);
}
[Route("")]
public IHttpActionResult Post([FromBody] NDTDocument ndtDocument)
{
try
{
Program.NDTServerSession.AddNDTDocument(ndtDocument);
return Ok();
}
catch(Exception ex)
{
return BadRequest(ex.Message);
}
}
}
And the client looks like this:
static void Main(string[] args)
{
AddNDTDocument(#"C:\Testing.txt");
}
private static void AddNDTDocument(string centralserverPath)
{
var client = GetServerClient();
NDTDocument document = new NDTDocument();
var response = client.PostAsJsonAsync("ndtdocument", document).Result;
}
static HttpClient GetServerClient()
{
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:9000/api/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
I can see when I debug it that the request uri is infact http://localhost:9000/api/ndtdocument
But the response is allways bad request and I have a breakpoint in the controller and it is never invoked.
Everytime I try to do something with web apis I Always run into some weird (but simple problem).
Any thoughts?
Thanks!
Web API will decide your route based on your method names. Since you have added [RoutePrefix("api/ndtdocument")] on class level this will be the route to your controller. When web api looks for an action it will match on method names, so in your case your actual route would be http://localhost:9000/api/ndtdocument/post.
When trying to decide what http method that a specific action requires web api will check your method names and methods starting with post will be http post, get will be http get etc.
So lets say we would instead call our method PostData, for starters we could remove the [HttpPost] attribute. Our route would now be http://localhost:9000/api/ndtdocument/postdata. Let's now say that we want our path to be just /data. We would then first rename our method to Data, but now web api does not know what http method we want to invoke this method with, thats why we add the [HttpPost] attribute.
Edit after reading your comment
[Route("{id:int}")]
public IHttpActionResult Get(int id)
[Route("")]
public IHttpActionResult Post([FromBody] NDTDocument ndtDocument)
Okey, after nearly going seriously insane. I found the problem.
I forgot to reference webapi.webhost and then system.web.
After this Everything worked like a charm.
You must use route tags and call this way http://localhost:9000/api/get or http://localhost:9000/api/post
[RoutePrefix("api/ndtdocument")]
public class NDTDocumentsController : ApiController, INDTDocumentsController
{
[HttpGet]
[Route("get")]
public IHttpActionResult Get()
{
var document = Program.NDTServerSession.GetNextNDTDocument(DateTime.Today);
if (document == null)
return null;
return Ok(document);
}
[HttpPost]
[Route("post")]
public IHttpActionResult Post([FromBody] NDTDocument ndtDocument)
{
try
{
Program.NDTServerSession.AddNDTDocument(ndtDocument);
return Ok();
}
catch(Exception ex)
{
return BadRequest(ex.Message);
}
}
}
for more infromation pls check this link