Reputation: 1339
I'm learning ASP.NET Core
and I have some doubts about the loading of an heavy collection of records, let me explain better.
What I'm trying to do
In my application, after the login execution, the user will redirected to the Dashboard Home View
. The Dashboard
is the place that contains all the functions for an user. The Dashboard Controller
have also other Views
like:
Now each View
need to display to the user a Table
which contains a list of Products
, at the bottom of this Table
there is the content of the View
.
Problem
First problem: is the Table
redundancy code, which I solved creating a _PartialView
that contains the html
of the Table
that contains the products to display. Coming from c# + WPF I used the same logic of UserControl
, so this is a good solution for me.
Second problem: the products to display inside the Table
, these products are downloaded from an API
, now as I said before, these records must be always displayed in the products Table
(which is available in different View
using the _PartialView
). Imagine that every time the user click on a Dashboard
item (which load a Dashboard View
), the Dashboard Controller
will call this method:
public async Task<List<Products>> GetProducts(string date)
{
var client = new RestClient(Url);
var request = new RestRequest("product/get_products/{date}", Method.GET);
request.AddUrlSegment("date", date);
var cancellationTokenSource = new CancellationTokenSource();
var response = await client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
List<Products> products = JsonConvert.DeserializeObject<List<Product>>(response.Content);
return products;
}
For me, this is not a really good practice because each time the _PartialView
will call this method and reload the data, so I need to store somehow this data (a temp store). How can I store these records to the user session without reload each time the _PartialView
being called?
Between, I have some doubts about the API
method:
Should I place all the API
calls inside the Service
folder? Repository
folder? Or Controller
folder?
Folder tree
View <- Folder
Dashboard <- Folder
Home
Analysis
Performance
_ProductsTable
The View
Home, Analysis, Performance
load _ProductsTable
in the following way:
@await Html.PartialAsync("_LeftSidebar")
Upvotes: 1
Views: 115
Reputation: 239400
Use view components. They're essentially self-contained modules of functionality that return views, which you can embed in other views, without main view or action having to know about any of it.
First, create a directory call ViewComponents
. Inside add new class, like ProductsViewComponent
. Then, you'll want something like:
public class ProductsViewComponent : ViewComponent
{
private readonly HttpClient _client;
public ProductsViewComponent(HttpClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IViewComponentResult> InvokeAsync(string date)
{
using (var response = await _client.GetAsync($"/"product/get_products/{date}"))
{
response.EnsureSuccessStatusCode();
var products = await response.Content.ReadAsAsync<List<Product>>();
return View(products);
}
}
}
Then, create the view, Views\Shared\Components\Products\Default.cshtml
. Inside, add the HTML to render your list of products. Finally, where you want the product table to appear add:
@await Component.InvokeAsync("Products", new { date = myDate })
The above code uses HttpClient
rather than RestClient
, since honestly, it's completely unnecessary at this point to have a separate library for making HTTP calls. HttpClient
is built-in and has been extended with functionality in Core to make this much easier, such as the ReadAsAsync
method used above, which transparently deserializes your JSON response into the generic type argument. Additionally, you now have things like IHttpClientFactory
which ensures that you have properly scoped HttpClient
instances. As a result, the above code also assumes adding something like the following to your Startup.cs
:
services.AddHttpClient<ProductsViewComponent>(c =>
{
c.BaseAddress = new Uri('https://api.myservice.com');
// add default headers and such if you need them
});
You can also then use the Polly integration to setup automatic retries, circuit breakers, etc., allowing you handle all sorts of API scenarios such as temporarily unavailable, rate limits, etc. See the full documentation for both IHttpClientFactory
and its Polly integration for more info.
Lastly, if this is a scenario where you don't need realtime data, you can also inject an instance of IDistributedCache
into your view component and add logic to set the result of your API call in that, and retrieve it from there first, before making the call again, allowing you to significantly reduce the load both on your app and the API (especially if do have something where rate limits apply).
Upvotes: 1