1

I'm encountering a 'MissingMethodException' MissingMethodException: Cannot dynamically create an instance of type 'Blazor.Pages.Account.Register'. Reason: No parameterless constructor defined in my Blazor server application when trying to use dependency injection with a non-parameterless constructor. Here's what I've tried so far:

I have created UserService.cs

using Blazor.API.Model;

namespace Blazor.Services
{
    public class UserService
    {
        private readonly HttpClient _httpClient;
        public UserService(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }

        public async Task<bool> RegisterAsync(RegisterModel registerModel)
        {
            try
            {
                var response = await _httpClient.PostAsJsonAsync("/register", registerModel);
                if (response.IsSuccessStatusCode)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }
    }
}

I have updated program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();


builder.Services.AddScoped<HttpClient>(s =>
{
    var httpClient = new HttpClient
    {
        BaseAddress = new Uri(builder.Configuration.GetSection("ApiBaseUrl").Value)
    };
    return httpClient;
});
builder.Services.AddHttpClient();
builder.Services.AddScoped<UserService>();
var app = builder.Build();

Also i am getting error "Warning CS8604 Possible null reference argument for parameter 'uriString' in 'Uri.Uri(string uriString)'" when i hover builder.Configuration.GetSection("ApiBaseUrl").Value

and My register.razor.cs

using Blazor.API.Model;
using Blazor.Services;

namespace Blazor.Pages.Account
{
    public partial class Register
    {
        private UserService UserService { get; set; }
        private bool isRegistering = false;
        private bool registrationSuccessful = false;
        private RegisterModel registerModel = new RegisterModel();
        
        public Register(UserService userService)
        {
            UserService = userService;
        }
        

        private async Task HandleValidSubmit()
        {
            // Start the registration process
            isRegistering = true;

            //send the registration request to the server
            bool registrationResult = await UserService.RegisterAsync(registerModel); 

            // Update the registration state
            registrationSuccessful = registrationResult;

            // Stop the registration process
            isRegistering = false;
        }
    }
}

However, when I navigate to this Registercomponent, I get the 'MissingMethodException' error. I have also tried adding a parameterless constructor, but it results in a 'Non-nullable property must contain a non-null value' warning.

How can I resolve this issue and properly use dependency injection with Blazor components that have non-parameterless constructors?

here is my register.razor

@page "/register"

<h3 class="text-center">Register</h3>
<div class="form-container">
<EditForm Model="@registerModel" OnValidSubmit="HandleValidSubmit" >
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="form-group">
        <label for="FirstName" class="form-label">First Name</label>
        <InputText id="FirstName" @bind-Value="registerModel.FirstName" class="form-control" />
        <ValidationMessage For="@(() => registerModel.FirstName)" />
    </div>

    <div class="form-group">
        <label for="LastName" class="form-label">Last Name</label>
        <InputText id="LastName" @bind-Value="registerModel.LastName" class="form-control" />
        <ValidationMessage For="@(() => registerModel.LastName)" />
    </div>

    <div class="form-group">
        <label for="Email" class="form-label">Email</label>
        <InputText id="Email" @bind-Value="registerModel.Email" class="form-control" />
        <ValidationMessage For="@(() => registerModel.Email)" />
    </div>

    <div class="form-group">
        <label for="PhoneNumber" class="form-label">Phone Number</label>
        <InputText id="PhoneNumber" @bind-Value="registerModel.PhoneNumber" class="form-control" />
        <ValidationMessage For="@(() => registerModel.PhoneNumber)" />
    </div>

    <div class="form-group">
        <label for="Password" class="form-label">Password</label>
        <InputText id="Password" @bind-Value="registerModel.Password" class="form-control" type="password" />
        <ValidationMessage For="@(() => registerModel.Password)" />
    </div>

        <div class="text-center">
            <button type="submit" class="btn btn-primary" disabled="@isRegistering">
                @if (isRegistering)
                {
                    <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
                    <text>Registering...</text>
                }
                else if (registrationSuccessful)
                {
                    <text>Registration Successful</text>
                }
                else
                {
                    <text>Register</text>
                }
            </button>
        </div>
        <p class="text-center mt-3">
        Already have an account? <a href="/login">Login here</a>
    </p>
</EditForm>
</div>

@code {
   
}

and my appSetting.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ApiBaseUrl": "https://localhost:44330/"
}

I'm a beginner in Blazor Server applications, and I'm currently trying to learn how to connect and interact with APIs in a Blazor Server application. Specifically, I'm working on implementing user registration and login functionality. However, I'm facing difficulties with setting up the HttpClient and establishing the correct flow for the registration process, as outlined in this post.

1
  • I have also tried adding a parameterless constructor, but it results in a 'Non-nullable property must contain a non-null value' warning - warnings are warnings, not errors. Does it work or do you get errors? Commented Sep 22, 2023 at 18:23

2 Answers 2

2

While most of @Sam's answer is correct. Couple of points I'd like to add.

That warning specifically is there because there is a chance that the "ApiBaseUrl" is not found in your appsettings.json or other configuration files. Now it's up to you to handle the case for when it can't be found i.e. null.

Here's two ways to handle it.

1. Handling null states

Using the the null conditional operator (?.) and the null coalescing operator (??) we can declare a "defaultUrl" for the case when "ApiBaseUrl" is null. Like so:-

BaseAddress = new Uri(builder.Configuration.GetSection("ApiBaseUrl")?.Value ?? "defaultUrl")

2. Surpressing warning with ! operator.

We can get rid of the warning by using the ! operator on the possible null object. This tells the compiler that Value is definitely not null. If it does end up not finding it then you will have a runtime NullReferenceException exception.

BaseAddress = new Uri(builder.Configuration.GetSection("ApiBaseUrl").Value!)

You shouldn't really use constructors in Blazor .razor files in general. You should use the blazor component lifecycles methods. Which means if you want to use dependency injection for blazor components then property injection should be used.

Here's how you use it in:-

  1. .razor component i.e. register.razor .
@inject UserService UserService
  1. .razor.cs code behind file i.e. register.razor.cs.
[Inject]
public UserService UserService { get; set; }

You can either declare it in the component or the code behind file. Typically if you have a code behind then you should declare it in there.

This is how you should change your register.razor.cs code using property injection.

namespace Blazor.Pages.Account
{
    public partial class Register
    {
        [Inject]
        public UserService UserService { get; set; }
        
        private bool isRegistering = false;
        private bool registrationSuccessful = false;
        private RegisterModel registerModel = new RegisterModel();       

        private async Task HandleValidSubmit()
        {
            // Start the registration process
            isRegistering = true;

            //send the registration request to the server
            bool registrationResult = await UserService.RegisterAsync(registerModel); 

            // Update the registration state
            registrationSuccessful = registrationResult;

            // Stop the registration process
            isRegistering = false;
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

The null error can be disabled by using the #nullable disable annotation at the top of the file, or when setting the service.

You're trying to inject a dependency through the constructor of your Register component. In Blazor, components are activated by the framework, which expects them to have a parameterless constructor. This allows Blazor to dynamically create instances of components as needed. If you provide a constructor with parameters but no parameterless constructor, Blazor will not know how to create an instance of that component, leading to the MissingMethodException.

MissingMethodException: Cannot dynamically create an instance of type 'Blazor.Pages.Account.Register'. Reason: No parameterless constructor defined. error.

Instead of using constructor injection for your Register component, you can use property injection.

    [Inject]
    public UserService UserService { get; set; }

Your register.razor file is missing the @code block that defines its backing C# class. This will integrate it with the the Razor UI. Note that null! is used to avoid the null error rather than the nullable anotation in the below code.

@code {
[Inject]
public UserService UserService { get; set; } = null!;

private bool isRegistering = false;
private bool registrationSuccessful = false;
private RegisterModel registerModel = new RegisterModel();

private async Task HandleValidSubmit()
{
    isRegistering = true;
    bool registrationResult = await UserService.RegisterAsync(registerModel);
    registrationSuccessful = registrationResult;
    isRegistering = false;
} }

Hope that helps!

1 Comment

Thank you very much for the help. Now it make sense to me. So if i want to inject in blazor I will use [Inject] private AccountService? AccountService { get; set; } and [Inject] private NavigationManager? NavigationManager { get; set; } and we cannot inject the dependency through constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.