2

I'm writing my first application using minimal APIs in a .NET 8 application. I'm following a training exercise I found on Microsoft Learn, and I'm using a database I designed. I ran into this error:

CS0311 The type 'Show1' cannot be used as type parameter 'TImplementation' in the generic type or method 'ServiceCollectionServiceExtensions.AddScoped<TService, TImplementation>(IServiceCollection)'. There is no implicit reference conversion from 'Show1' to 'BlazorMediaLibrary.API.Interfaces.IShow1'

I searched this error and came up with Why does a generic type constraint result in a no implicit reference conversion error? here on SO. However, I don't think this fits my situation. Here's what I got for my Interface, which was generated when I scaffolded the database to create the model classes and DbContext:

public interface IShow1
{
    int ShowId { get; set; }
    int ShowCode { get; set; }
    string EpisodeName { get; set; }
    string? Synopsis { get; set; }
    DateTime? DateLastViewed { get; set; }
    DateTime? OriginalBroadcastDate { get; set; }
    TimeOnly? PlayTime { get; set; }
    double? Rating { get; set; }

    TypeOfShow1 ShowCodeNavigation { get; set; }
    ICollection<Entries2> Entries2s { get; set; }
    ICollection<UserRating> UserRatings { get; set; }
}

and here's the model class implementation:

public partial class Show1 : IShow1
{
    public int ShowId { get; set; }

    public int ShowCode { get; set; }

    public string EpisodeName { get; set; } = null!;

    public string? Synopsis { get; set; }

    public DateTime? DateLastViewed { get; set; }

    public DateTime? OriginalBroadcastDate { get; set; }

    public TimeOnly? PlayTime { get; set; }

    public double? Rating { get; set; }

    public virtual TypeOfShow1 ShowCodeNavigation { get; set; } = null!;
    public virtual ICollection<Entries2> Entries2s { get; set; } = new List<Entries2>();
    public virtual ICollection<UserRating> UserRatings { get; set; } = new List<UserRating>();
}

In the Program.cs file I defined this record:

internal record Show1(int ShowId, int ShowCode, string EpisodeName,
                      string? Synopsis, DateTime? DateLastViewed, 
                      DateTime? OriginalBoardcastDate, TimeOnly? PlayTime, float? Rating);

And here's the line in Program.cs which is raising the error:

builder.Services.AddScoped<IShow1, Show1>();

I didn't include ShowCodeNavigation, Entries2 or UserRatings in the record definition in Program.cs.

Is that what's causing my problem?

4
  • 1
    Are you absolutely sure that the IShow1 interface that your class implements is the same one you're trying to use, i.e. BlazorMediaLibrary.API.Interfaces.IShow1? If you put your cursor in IShow1 in the class declaration (where you're declaring that you implement it) and press F12, which interface does it go to? Commented Aug 3, 2024 at 14:50
  • When I hover my mouse over IShow1 in the Show1 class in the Models folder, it indicates the interface in BlazorMediaLibrary.API.Interfaces. In the Program.cs file, the IShow1 interface used in builder.Services.AddScoped() also indicates the interface in BlazorMediaLibrary.API.Interfaces. And the Show1 class in the same builderr.Services.AddScoped() points to the Show1 class in the Models folder. Commented Aug 4, 2024 at 2:04
  • For grins and giggles, I thought I'd comment out the two using statements at the top of the Program.cs file, then I replaced the builder.Services.AddScoped with this: builder.Services.AddScoped<BlazorMediaLibrary.API.Interfaces.IShow1, BlazorMediaLibrary.API.Models.Show1>(); That cleared up the errors. I don't get why that cleared up the errors. Commented Aug 4, 2024 at 2:10
  • 2
    I'd missed that you'd defined a record called Show1 as well. I strongly suspect that was the problem - note that in the error message, it's not referring to BlazorMediaLibrary.API.Models.Show1, just Show1. Aside from anything else, having both a class and a record called Show1 would be confusing to any humans working with the code... Commented Aug 4, 2024 at 6:39

1 Answer 1

1

In the Program.cs file I defined this record: internal record Show1 ...

It will "shadow" the Show1 which implements the interface and is "imported" via corresponding using statement. I would recommend to rename the record to something else, but if there is a very good reason to have both internal record and class with the same name (I can't think of one but still), you can use the "full" type name for the registration:

builder.Services.AddScoped<IShow1, BlazorMediaLibrary.API.Models.Show1>();

If the record is not used in the top-level statement code (i.e. in the Program.cs) then you can switch to the "explicit" Main method (see Should 'using' directives be inside or outside the namespace in C#? for some possible explanation):

namespace MyNamespace
{
    using BlazorMediaLibrary.API.Models; // moving import out of the namespace will break the compilation

    public class Program
    {
        public void Main()
        {
            new ServiceCollection()
                .AddScoped<IShow1, Show1>();
        }
    }
}

internal record Show1(int ShowId, ...);

or moving record to some namespace:

// in Program.cs
app.Run();

namespace MyNamespace
{
    internal record Show1(...);
}

In your current code internal record Show1 results in the record class generated in the global namespace which results in the behavior your observe.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the explanation! I wanted to know what was going on and why. I appreciate it.

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.