asp.net-corerazorblazor-webassembly

Return Single record from JSON Data file in Blazor WASM


New to Blazor and I am migrating an old site to help learn.

This is a classic list all items, click Item to view details scenario

I have done the list all items in 1 page "Portfolio" using the following (which works perfect)

@code {
    private artWork[]? artWorks;

    protected override async Task OnInitializedAsync()
    {
       
            artWorks = await Http.GetFromJsonAsync<artWork[]>("data/artwork.json");
       
    }

    public class artWork
    {
        public int artworkID { get; set; }
        public string? artworkName { get; set; }
        public string? artworkFilename { get; set; }
        public string? description { get; set; }
        public string? artworkMediumID { get; set; }
        public string? price { get; set; }
        public string? width { get; set; }
        public string? height { get; set; }
    }

}

and I have a for each like so

@foreach (var artWork in artWorks)
{

<div class="art-wrapper">
    <div class="img-thumb">
        <a href="img/artwork/@artWork.artworkFilename" ToolTip="@artWork.artworkName - By Trevor Bollen" title="@artWork.artworkName - By Trevor Bollen">
            <img src="img/artwork/@artWork.artworkFilename.Replace(".jpg", "_thumb.jpg")" title="@artWork.artworkName - By Trevor Bollen" alt="@artWork.artworkName - By Trevor Bollen" />
        </a>
    </div>
    <div class="art-info">
        <h3>@artWork.artworkName</h3>
        <p><b>Medium:</b> @artWork.artworkMediumID </p>
        <p><b>Size:</b> @artWork.width x @artWork.height (cm) </p>
        <p><b>Price:</b> £@artWork.price</p>
    <p><a href="portfoliodetail/@artWork.artworkID"><img src="img/btn-detail-sml.jpg" Class="btnViewDetail" AlternateText="Click here to view artwork details" ToolTip="Click here to view artwork details" /></a></p>
    </div>
</div>


}

Which links through to the portfoliodetail page with Parameter. My question is, on this page how do I get the single record from my JSON using the ID passed through? So far I have the following but not sure how to filter or get by ID

@code {
private artWork? artWorks;

protected override async Task OnInitializedAsync()
{
   
        artWorks = await Http.GetFromJsonAsync<artWork>("data/artwork.json");
   
}

public class artWork
{
    public int artworkID { get; set; }
    public string? artworkName { get; set; }
    public string? artworkFilename { get; set; }
    public string? description { get; set; }
    public string? artworkMediumID { get; set; }
    public string? price { get; set; }
    public string? width { get; set; }
    public string? height { get; set; }
}

}

Sample of Data shown below.

enter image description here


Solution

  • Here's a fairly simple example using a service to get and cache the Json data and provide methods to get a collection or a single object.

    This example is based on getting this simple record:

    public record CountryRecord(string Country, string Continent);
    

    A Repository Service to get and cache the data:

    public class CountryRepository
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private List<CountryRecord> _countries = new();
        private Task? _getDataTask;
        private object _lock = new();
    
        public CountryRepository(IHttpClientFactory httpClientFactory)
        {
            _httpClientFactory = httpClientFactory;
        }
    
        public async ValueTask<IEnumerable<CountryRecord>> GetItemsAsync()
        {
            await GetData();
            return _countries;
        }
    
        public async ValueTask<CountryRecord?> GetItemAsync(string country)
        {
            await GetData();
            return _countries.FirstOrDefault(item => item.Country.Equals(country));
        }
    
        private Task GetData()
        {
            if (_getDataTask is not null)
                return _getDataTask;
    
            // ensures only one process can start the Task
            lock (_lock)
            {
                if (_getDataTask is null)
                    _getDataTask = this.GetHttpDataAsync();
            }
    
            return _getDataTask;
        }
    
        private async Task GetHttpDataAsync()
        {
            var httpClient = _httpClientFactory.CreateClient();
            var countries = await httpClient.GetFromJsonAsync<List<CountryRecord>>("https://localhost:7191/sample-data/countries.json");
            ArgumentNullException.ThrowIfNull(countries, "Json file not found.");
            _countries = countries;
        }
    }
    

    And the registered service:

    builder.Services.AddHttpClient();
    builder.Services.AddSingleton<CountryRepository>();
    

    You can now inject the service into any page/component and either get the full collection by calling GetItemsAsync or a single item by calling GetItemAsync.