18

How to make the View returned by the controller and generated by Razor get the data from the api i want to keep the razor engine view and use the api the original mvc controller returns the view with the data as parameter now i want the data from the api

MVC controller

public class ProductController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

Api Controller

public class ProductsController : ApiController
{
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET api/Products
    public IEnumerable<Product> GetProducts()
    {
        return db.Products;
    }
}

Model:

@model IEnumerable<WebApplication2.Models.Product>

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
    <th>
        @Html.DisplayNameFor(model => model.Name)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Category)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Price)
    </th>
    <th></th>
</tr>

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Name)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Category)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Price)
    </td>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
        @Html.ActionLink("Details", "Details", new { id=item.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id=item.Id })
    </td>
</tr>
}
</table>
abatishchev
  • 98,240
  • 88
  • 296
  • 433
user3353484
  • 189
  • 1
  • 1
  • 8
  • I'm on a project to learn the roles of M,V, and C in Razor. I believe what you label "Model:" should be labeled View instead. Model in this example is only a list of Models.Product objects which the Controller produces. – Alan Baljeu Jan 13 '20 at 15:35

4 Answers4

21

You could send an HTTP request to your Web API controller from within the ASP.NET MVC controller:

public class ProductController : Controller
{
    public ActionResult Index()
    {
        var client = new HttpClient();
        var response = client.GetAsync("http://yourapi.com/api/products").Result;
        var products = response.Content.ReadAsAsync<IEnumerable<Product>>().Result;
        return View(products);
    }
}

Also if you can take advantage of the .NET 4.5 async/await it is strongly recommended to do so to avoid blocking calls:

public class ProductController : Controller
{
    public async Task<ActionResult> Index()
    {
        var client = new HttpClient();
        var response = await client.GetAsync("http://yourapi.com/api/products");
        var products = await response.Content.ReadAsAsync<IEnumerable<Product>>();
        return View(products);
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • i created a html client that calls the api using url /api/products it worked but there is a problem with the ("http://yourapi.com/api/products") what should i put here exactly ?? – user3353484 Mar 03 '14 at 12:53
  • You should put the url of your Web API endpoint returning the list of products. – Darin Dimitrov Mar 03 '14 at 12:55
  • thank you !! Can I replace the url by @Url.Action ?? – user3353484 Mar 03 '14 at 12:59
  • That would depend on whether the Web API is hosted in the same ASP.NET host as your ASP.NET MVC application. Otherwise you cannot expect the client application to know anything about the routing configured on the server side. If both applications are hosted in the same host you could use the `RouteUrl` helper: `string productsUrl = Url.RouteUrl("DefaultApi", new { httproute = "", controller = "products" });`. – Darin Dimitrov Mar 03 '14 at 13:01
  • Be careful when you start using load balancers or reverse proxies that get assigned the `yourapi.com` DNS name and that have specific rules to block too many requests from a single client or when rewriting requests and such (SSL offloading is one such example). Also be mindful of the performance impact of roundtrips over the network in such case. – Dave Van den Eynde Apr 07 '14 at 07:41
  • Is calling your own web api just to access your readmodels a good thing? – Léon Pelletier Aug 25 '15 at 17:06
21

Read here on how to use the Razor view engine inside your Web API controller. The interesting part is using the RazorEngine NuGet package to do the heavy lifting.

twoflower
  • 6,788
  • 2
  • 33
  • 44
  • Thanks for the useful link. – Pavel Bastov Jun 25 '15 at 05:04
  • 1
    Your answer is definitely better answer than doing HTTP request from MVC to API controller. I do not know why that answer has so many upvotes but from performance pov it is nonsense to do it. – Regfor Jan 22 '18 at 09:04
1

The basis of the link supplied by twoflower is to have your handlers create and return an instance of a custom IHttpActionResult implementation. A simplified example is shown below:

public class TestHttpActionResult : IHttpActionResult
{
    private readonly HttpRequestMessage _request;
    private readonly string _responseString;

    public TestHttpActionResult(HttpRequestMessage request, string responseString)
    {
        _request = request;
        _responseString = responseString;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = _request.CreateResponse(HttpStatusCode.Created);
        response.Content = new StringContent(_responseString);
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
        return Task.FromResult(response);
    }
}
andrew pate
  • 3,833
  • 36
  • 28
0

You can return a string in response by using

return Ok(".....");