LazZiya / XLocalizer

Localizer package for Asp.Net Core web applications, powered by online translation and auto resource creating.
https://docs.ziyad.info
128 stars 14 forks source link

Exception: Cannot create a DbSet for 'XDbResource' because this type is not included in the model for the context. #14

Closed morgrowe closed 3 years ago

morgrowe commented 3 years ago

Hi Ziya

This exception (pasted at the end) is thrown whenever I use an EditorTemplate. For example:

@Html.LabelFor(model => model.LoginViewModel.Email) // doesn't throw exception here
@Html.EditorFor(model => model.LoginViewModel.Email, new { htmlAttributes = new { @class = "form-control" } })

I think it's saying it can't find the XDbResource entity in my DbContext. I'm not using the XDbResource entity directly, I've created my own classes that implement IXDbResource. This has worked perfectly when using the IStringLocalizer in my controllers.

My DbContext looks like this:

public class DashboardDbContext : IdentityDbContext<IdentityUser>, IDashboardDbContext, ILocalizationDbContext
    {
        // DI, ctor and other DbSets

        public DbSet<XDbCulture> XDbCultures { get; set; }

        public DbSet<DomainLocalizationResource> DomainLocalizationResources { get; set; }

        public DbSet<UserLocalizationResource> UserLocalizationResource { get; set; }

       // methods...
   }

In my Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            // other configurations

            services.AddRazorPages()
                .AddRazorPagesOptions((ops) => {
                    ops.Conventions.Insert(0, new RouteTemplateModelConventionRazorPages());
                })
                .AddXDbLocalizer<DashboardDbContext>((opts) =>
                {
                    opts.UseExpressMemoryCache = false;
                });
        }

Any idea what's going on? I've probably misconfigured XLocalizer. Maybe XLocalizer look specifically for the XDbResource DbSet when attempting to localize EditorTemplates?

Thanks, as always. Morgan

System.InvalidOperationException: Cannot create a DbSet for 'XDbResource' because this type is not included in the model for the context.
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsNoTracking[TEntity](IQueryable`1 source)
   at XLocalizer.DB.EF.EFDbResourceProvider`1.TryGetValue[TResource](String key, String& value)
   at XLocalizer.DB.DbStringLocalizer`1.GetLocalizedString(String name, Object[] arguments)
   at XLocalizer.DB.DbStringLocalizer`1.get_Item(String name, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.DataAnnotations.ValidationAttributeAdapter`1.GetErrorMessage(ModelMetadata modelMetadata, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.DataAnnotations.RequiredAttributeAdapter.GetErrorMessage(ModelValidationContextBase validationContext)
   at Microsoft.AspNetCore.Mvc.DataAnnotations.RequiredAttributeAdapter.AddValidation(ClientModelValidationContext context)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultValidationHtmlAttributeProvider.AddValidationAttributes(ViewContext viewContext, ModelExplorer modelExplorer, IDictionary`2 attributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ValidationHtmlAttributeProvider.AddAndTrackValidationAttributes(ViewContext viewContext, ModelExplorer modelExplorer, String expression, IDictionary`2 attributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.AddValidationAttributes(ViewContext viewContext, TagBuilder tagBuilder, ModelExplorer modelExplorer, String expression)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, String expression, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, String format, IDictionary`2 htmlAttributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateTextBox(ViewContext viewContext, ModelExplorer modelExplorer, String expression, Object value, String format, Object htmlAttributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.GenerateTextBox(ModelExplorer modelExplorer, String expression, Object value, String format, Object htmlAttributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.TextBox(String expression, Object value, String format, Object htmlAttributes)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultEditorTemplates.GenerateTextBox(IHtmlHelper htmlHelper, String inputType)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultEditorTemplates.EmailAddressInputTemplate(IHtmlHelper htmlHelper)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.TemplateRenderer.Render()
   at Microsoft.AspNetCore.Mvc.ViewFeatures.TemplateBuilder.Build()
   at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper.GenerateEditor(ModelExplorer modelExplorer, String htmlFieldName, String templateName, Object additionalViewData)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.HtmlHelper`1.EditorFor[TResult](Expression`1 expression, String templateName, String htmlFieldName, Object additionalViewData)
   at Microsoft.AspNetCore.Mvc.Rendering.HtmlHelperEditorExtensions.EditorFor[TModel,TResult](IHtmlHelper`1 htmlHelper, Expression`1 expression, Object additionalViewData)
   at Caforb.DashboardUI.Pages.Pages_Login.ExecuteAsync() in Z:\caforb\Src\Caforb.DashboardUi\Pages\Login.cshtml:line 19
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
LazZiya commented 3 years ago

Hi @morgrowe ,

I know I have to work more on documentations, but it is time matter :)

There is different variations for .AddXDbLocalizer<...>:

// Add XLocalizer with database support using the default built-in entity models
.AddXDbLocalizer<TContext>( ops => { ... });

// Add XLocalizer with database support using the default built-in entity models,
// and use defined translation service type
.AddXDbLocalizer<TContext, TTranslator>(ops => { ... });

// Add XLocalizer with database support using customized entity models,
// and use defined translation service type
.AddXDbLocalizer<TContext, TTranslator, TResource>(ops => { ... });

First two methods will use the default entity model (defautl db set) which is XDbResource. But if you want to use custom db set you have to use the latest method.

.AddXDbLocalizer<DashboardDbContext, MyTranslationService, DomainLocalizationResource>((opts) =>
{
    opts.UseExpressMemoryCache = false;
});

Reason why:

// In this case IStringLocalizer will search for localized values in XDbResource
.AddXDbLocalizer<TContext>( ops => { ... });

// In this case IStringLocalizer will search for localized values in XDbResource
.AddXDbLocalizer<TContext, TTranslator>(ops => { ... });

// In this case IStringLocalizer will search for localized values in TResource
.AddXDbLocalizer<TContext, TTranslator, TResource>(ops => { ... });
morgrowe commented 3 years ago

No problem. I really appreciate all the time and effort you've put into this tool. The documentation answers the grand majority of my queries, too. :)

I changed my .AddDbLocalizer to:

    .AddXDbLocalizer<DashboardDbContext, ITranslator, DomainLocalizationResource>((opts) =>
    {
        opts.UseExpressMemoryCache = false;
    });

And now my page renders without an exception. Thank you!

I'm not using the ITranslator feature at the moment. I tried passing null as the second parameter but it didn't like it. Is it ok to just pass ITranslator?

Thank you very much!

Morgan

LazZiya commented 3 years ago

You are welcome @morgrowe

Instead of passing ITranslator you can use the already available DummyTranslator and set auto translate to false:

.AddXDbLocalizer<DashboardDbContext, DummyTranslator, DomainLocalizationResource>((opts) =>
{
    ops.AutoTranslate = false;
    opts.UseExpressMemoryCache = false;
});

The dummy translator will throw an exception if auto translate is set to true.

morgrowe commented 3 years ago

You have thought of everything. That's perfect, thank you very much. :)

Morgan