locked
How do i write this code RRS feed

  • Question

  • User2041008840 posted

    service.cs

    readonly IAccessTokenProvider _accessTokenProvider;
          readonly  NavigationManager NavigationManager;
            public async Task<List<ScheduleViewModel>> GetSchedulesAsync(int setupID)
            {
                HttpClient http = new HttpClient();
                http.BaseAddress = new Uri(NavigationManager.BaseUri);
                var tokenResult = await _accessTokenProvider.RequestAccessToken();
                if (tokenResult.TryGetToken(out var token))
                {
                    http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
                    var json = await http.GetStringAsync($"api/Schedules?setupID={setupID}");
                    return JsonConvert.DeserializeObject<List<ScheduleViewModel>>(json);
                }
                return null;
            }
    index.razor
    @inject IAccessTokenProvider AccessTokenProvider
    var httpClient = new HttpClient(); httpClient.BaseAddress = new System.Uri(NavigationManager.BaseUri); var tokenResult = await AccessTokenProvider.RequestAccessToken(); if (tokenResult.TryGetToken(out var token)) { httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}"); schedules = await httpClient.GetFromJsonAsync<List<ScheduleViewModel>>("api/schedules?setupid=2"); }

    both code are same but difference is one is in .cs file were I put all my all api call from json to desrerializeObject . 
    And other is in .razor 

    the .razor code accept access token and run perfectly. but .cs file code does not accept access code and show error object ref. not set to any instance obj, 

    so How do i write and get work successfully

    Wednesday, February 17, 2021 7:34 PM

Answers

  • User1535942433 posted

    Hi Prathamesh Shende,

    As far as I think,I guessing that you have registered,but AccessTokenProvider's value is null.You only create the property but not add in the constructor.

    You could do like this:

    public class TestService {
    
        private  readonly IAccessTokenProvider _accessTokenProvider; 
    
        private  readonly NavigationManager _NavigationManager;
            public TestService(IAccessTokenProvider accessTokenProvider,NavigationManager NavigationManager){
    
            _accessTokenProvider=accessTokenProvider;
    
            _NavigationManager=NavigationManager;
    
          }
    }

    More details,you could refer to below article:

    https://docs.microsoft.com/en-us/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-5.0

    Best regards,

    Yijing Sun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 18, 2021 5:53 AM
  • User475983607 posted

    I provided an entire working example where the Blazor application is configured to add the bearer token to the HttpClient.  Why are you manually adding the token?  Makes no sense...

    Also, your HttpClient design is not recommended.  You should create an HttpClient factory or named type.  Why did you move form best practices to a poor design?

    Edit:  Below is a sample service using the standards we already built in your other threads.

    Service

        public interface IWebApiClient
        {
            Task<WeatherForecast[]> GetWeatherForecast();
        }
    
        public class WebApiClient : IWebApiClient
        {
            private HttpClient _client;
            public WebApiClient(HttpClient client)
            {
                _client = client;
            }
    
            public async Task<Models.WeatherForecast[]> GetWeatherForecast()
            {
                return await _client.GetFromJsonAsync<Models.WeatherForecast[]>("WeatherForecast");
            }
        }

    Dependency injection

        public class Program
        {
            public static async Task Main(string[] args)
            {
                var builder = WebAssemblyHostBuilder.CreateDefault(args);
                builder.RootComponents.Add<App>("#app");
    
                builder.Services.AddHttpClient("api", s =>
                {
                    s.BaseAddress = new Uri("https://localhost:5002");
                    s.DefaultRequestHeaders.Add("Accept", "application/json");
                })
                    .AddHttpMessageHandler(sp =>
                    {
                        var handler = sp.GetService<AuthorizationMessageHandler>()
                            .ConfigureHandler(
                                authorizedUrls: new[] { "https://localhost:5002" },
                                scopes: new[] { "weatherapi" });
                        
                        return handler;
                    });
    
                builder.Services.AddScoped(sp => sp.GetService<IHttpClientFactory>().CreateClient("api"));
    
                builder.Services.AddOidcAuthentication(options =>
                {
                    builder.Configuration.Bind("oidc", options.ProviderOptions);
                });
    
                builder.Services.AddScoped<IWebApiClient, WebApiClient>();
    
                await builder.Build().RunAsync();
            }
        }

    Implementation

    @page "/fetchdata"
    @inject HttpClient Http
    @inject BlazorClient.Services.IWebApiClient client
    @attribute [Authorize]
    
    <h1>Weather forecast</h1>
    
    <p>This component demonstrates fetching data from the server.</p>
    
    @if (forecasts == null)
    {
        <p><em>Loading...</em></p>
    }
    else
    {
        <table class="table">
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Temp. (C)</th>
                    <th>Temp. (F)</th>
                    <th>Summary</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var forecast in forecasts)
                {
                    <tr>
                        <td>@forecast.Date.ToShortDateString()</td>
                        <td>@forecast.TemperatureC</td>
                        <td>@forecast.TemperatureF</td>
                        <td>@forecast.Summary</td>
                    </tr>
                }
            </tbody>
        </table>
    }
    
    @code {
        private Models.WeatherForecast[] forecasts;
    
        protected override async Task OnInitializedAsync()
        {
            //forecasts = await Http.GetFromJsonAsync<Models.WeatherForecast[]>("WeatherForecast");
            forecasts = await client.GetWeatherForecast();
        }
    
    }
    

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 18, 2021 11:33 AM

All replies

  • User475983607 posted

    You did not share all the relevant code, what's null, or even the client framework.  I don't get it!  The exception always displays the code that caused the null exception.  Why hide this information when asking for assistance?

    I recommend good old debugging.

    Wednesday, February 17, 2021 8:08 PM
  • User2041008840 posted
    var tokenResult = await AccessTokenProvider.RequestAccessToken(); // this part show null - Object reference not set  to an instant object....

    That IAccessTokenProvider works correctly in .razor page. 
    same thing I tried in services.cs file it does not work. why?

    Thursday, February 18, 2021 3:22 AM
  • User1535942433 posted

    Hi Prathamesh Shende,

    As far as I think,I guessing that you have registered,but AccessTokenProvider's value is null.You only create the property but not add in the constructor.

    You could do like this:

    public class TestService {
    
        private  readonly IAccessTokenProvider _accessTokenProvider; 
    
        private  readonly NavigationManager _NavigationManager;
            public TestService(IAccessTokenProvider accessTokenProvider,NavigationManager NavigationManager){
    
            _accessTokenProvider=accessTokenProvider;
    
            _NavigationManager=NavigationManager;
    
          }
    }

    More details,you could refer to below article:

    https://docs.microsoft.com/en-us/aspnet/core/mvc/views/dependency-injection?view=aspnetcore-5.0

    Best regards,

    Yijing Sun

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 18, 2021 5:53 AM
  • User2041008840 posted

    Hello, 
    this is my code its in blazor WASM
        index.razor
        @inject IAccessTokenProvider accessTokenProvider;

    @inject StagesService StageService
        @foreach(var item in Stagecount)
        {
        @item.Name
        }
        
          protected override async Task OnInitializedAsync()
            {
        HttpClient http= new HttpClient();
                   http.BaseAddress = new Uri("https://localhost:44348/");
                   http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
                    var tokenResult = await accessTokenProvider.RequestAccessToken();
                    if (tokenResult.TryGetToken(out var token))
                    {
                        http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
         Stagescount = await http.GetFromJsonAsync<List<StageViewModel>>($"{apiUrl.BaseUrl}api/Schedules?setupID={setupID}");
         
        }
        
        
        StageServices.cs
        readonly IAccessTokenProvider accessTokenProvider;
         public class StagesService
            {
           private readonly IAccessTokenProvider _accessTokenProvider;
            public StagesService(IAccessTokenProvider accessTokenProvider)
            {
                _accessTokenProvider = accessTokenProvider;
            }
         public async Task<List<Stage>> GetStagesAsync(int setupID)
                {
        HttpClient http= new HttpClient();
                   http.BaseAddress = new Uri("https://localhost:44348/");
                   http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
                    var tokenResult = await accessTokenProvider.RequestAccessToken();
                    if (tokenResult.TryGetToken(out var token))
                    {
                        http.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Value}");
                    var json = await http.GetFromJsonAsync<List<StageViewModel>>($"{apiUrl.BaseUrl}api/Schedules?setupID={setupID}");
                    HttpClient http = new HttpClient();
        
                    return JsonConvert.DeserializeObject<List<Stage>>(json);
                }
        }

    Program.cs
    builder.Services.AddSingleton<StagesService>();


    IAccessTokenProvider works fine and aceess the Access Token in index.razor and Api will work fine. 

    but in StagesService file IAccessTokenProvider does not accept the access token and not showing error object ref not set to an instant obj. 

    so How do i write the and get access token in stageservices.cs 
    if I add the StagesService.GetStagesAsync into OnInitializedAsync() It will call list and and access token before it. 

    error -  Unhandled exception rendering component: Cannot consume scoped service 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider' from singleton 'Project.Client.Services.StagesService'.

    Thursday, February 18, 2021 9:08 AM
  • User475983607 posted

    I provided an entire working example where the Blazor application is configured to add the bearer token to the HttpClient.  Why are you manually adding the token?  Makes no sense...

    Also, your HttpClient design is not recommended.  You should create an HttpClient factory or named type.  Why did you move form best practices to a poor design?

    Edit:  Below is a sample service using the standards we already built in your other threads.

    Service

        public interface IWebApiClient
        {
            Task<WeatherForecast[]> GetWeatherForecast();
        }
    
        public class WebApiClient : IWebApiClient
        {
            private HttpClient _client;
            public WebApiClient(HttpClient client)
            {
                _client = client;
            }
    
            public async Task<Models.WeatherForecast[]> GetWeatherForecast()
            {
                return await _client.GetFromJsonAsync<Models.WeatherForecast[]>("WeatherForecast");
            }
        }

    Dependency injection

        public class Program
        {
            public static async Task Main(string[] args)
            {
                var builder = WebAssemblyHostBuilder.CreateDefault(args);
                builder.RootComponents.Add<App>("#app");
    
                builder.Services.AddHttpClient("api", s =>
                {
                    s.BaseAddress = new Uri("https://localhost:5002");
                    s.DefaultRequestHeaders.Add("Accept", "application/json");
                })
                    .AddHttpMessageHandler(sp =>
                    {
                        var handler = sp.GetService<AuthorizationMessageHandler>()
                            .ConfigureHandler(
                                authorizedUrls: new[] { "https://localhost:5002" },
                                scopes: new[] { "weatherapi" });
                        
                        return handler;
                    });
    
                builder.Services.AddScoped(sp => sp.GetService<IHttpClientFactory>().CreateClient("api"));
    
                builder.Services.AddOidcAuthentication(options =>
                {
                    builder.Configuration.Bind("oidc", options.ProviderOptions);
                });
    
                builder.Services.AddScoped<IWebApiClient, WebApiClient>();
    
                await builder.Build().RunAsync();
            }
        }

    Implementation

    @page "/fetchdata"
    @inject HttpClient Http
    @inject BlazorClient.Services.IWebApiClient client
    @attribute [Authorize]
    
    <h1>Weather forecast</h1>
    
    <p>This component demonstrates fetching data from the server.</p>
    
    @if (forecasts == null)
    {
        <p><em>Loading...</em></p>
    }
    else
    {
        <table class="table">
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Temp. (C)</th>
                    <th>Temp. (F)</th>
                    <th>Summary</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var forecast in forecasts)
                {
                    <tr>
                        <td>@forecast.Date.ToShortDateString()</td>
                        <td>@forecast.TemperatureC</td>
                        <td>@forecast.TemperatureF</td>
                        <td>@forecast.Summary</td>
                    </tr>
                }
            </tbody>
        </table>
    }
    
    @code {
        private Models.WeatherForecast[] forecasts;
    
        protected override async Task OnInitializedAsync()
        {
            //forecasts = await Http.GetFromJsonAsync<Models.WeatherForecast[]>("WeatherForecast");
            forecasts = await client.GetWeatherForecast();
        }
    
    }
    

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Thursday, February 18, 2021 11:33 AM
  • User2041008840 posted

    Also, your HttpClient design is not recommended.  You should create an HttpClient factory or named type.  Why did you move form best practices to a poor design?


    Yes, I understood. I was moving to bad design. The code that I was writing was long and poor. 
    have changes the code and fetch direct data into .Razor pages 

    I removed all Service.cs file 
    and create a class file where i only store baseAddress and "api/" and just pass the controller name and parameters. 

    Thanks for your help @mgebhard

    Saturday, February 20, 2021 5:58 AM