如何为 html title 属性设计 InfoHelper

How to design InfoHelper for html title attribute

对于 Asp.net mvc 核心应用程序: 在我的一个 dbcontext 表中,我有 HelpInfo 的记录(id 作为主键,helpInfo 的字符串),我想在我的 razor 视图中用作 html 标题属性,例如:

<div title='@I(12)'></div>

其中 12 是 HelpInfo 记录的示例 ID,@I 应该是全局可访问的 class 方法,用于获取相应的 helpInfo 字符串。

我尝试实施 King Kings 方法,例如:

自定义视图:

public abstract class CustomView<TModel>  : RazorPage<TModel>
{
    protected IInfo Info => Context.RequestServices.GetRequiredService<IInfo>();

    public Task<string> I(int code)
    {
        return Info.GetAsync(code);
    }
}

接口:

public interface IInfo
{
    Task<string> GetAsync(int code);
}

服务:

public class Info : IInfo
{
    private readonly ApplicationDbContext context;
    public Info(ApplicationDbContext context)
    {
        this.context = context;
    }

    public async Task<string> GetAsync(int code)
    {
        var myRecord = await context.MyRecords.FindAsync(code);
        if (myRecord != null)
        {
            return myRecord.Info;
        }
        return null;
    }
}

在_ViewImports.cshtml中我添加了@inherits CustomView<TModel>

在视图中我使用了<div title='@(await I(12))'>Test</div>

当我加载视图时,我得到

No service for type '...Models.IInfo' has been registered

如能帮助解决问题,我们将不胜感激。

据我了解,您似乎想要 @Html@Url 之类的东西,它们在默认 PageRazorPage 中受支持。这只是基本页面公开的自定义 属性。因此,在您的情况下,您需要一个自定义视图(对于 mvc)或一个自定义页面(对于 razor 页面)。这是用于 MVC 的自定义视图的示例:

public abstract class CustomView<TModel> : RazorPage<TModel>
{              
    //custom members can be declared in here
}

根据您希望使用的 I,它必须是一个方法。所以它可以是在您的基本页面中注入的某些服务公开的方法。假设界面是这样的:

public interface IInfo {
     string Get(int code);
}

现在您的自定义页面可以像这样实现 I 方法:

public abstract class CustomView<TModel> : RazorPage<TModel>
{      
    //NOTE: the custom page class does not support constructor injection
    //So we need to get the injected services via the Context like this.
    protected IInfo Info => Context.RequestServices.GetRequiredService<IInfo>();        
    public string I(int code){
       return Info.Get(code);
    }
}

要使用您的自定义视图,您需要在视图中使用指令 @inherits 或在 _ViewImports.cshtml 中使用更好的指令,这样您就不必在任何地方重复 @inherits ,像这样:

@inherits CustomView<TModel>

有时在重建项目之前不会应用基础视图(因此基础成员不可用)。

现在您可以根据需要在视图中使用 I,如下所示:

<div title="@I(12)"></div>

注意在我的示例中 I 方法 return 是 string,您也可以将其设为 return 和 IHtmlContent(例如:HtmlString) 或您需要的任何类型。

注意:

从技术上讲,您可以使用任何服务(包括从数据库查询数据的服务),但在这种情况下,请确保查询速度尽可能快,并使用 async 以获得最佳性能并避免线程饥饿。这是从数据库查询的 IInfo 服务的示例:

public interface IInfo {
     Task<string> GetAsync(int code);
}

public class Info : IInfo {
     //inject whatever your Info needs
     //here we just need some DbContext (used in EFCore)
     public Info(InfoDbContext dbContext){
        _infoDbContext = dbContext;
     }
     readonly InfoDbContext _infoDbContext;
     public async Task<string> GetAsync(int code){
         var info = await _infoDbContext....
         return info;
     }
}

I 方法也应该是 async:

public Task<string> I(int code){
       return Info.GetAsync(code);
}

我希望您知道如何注册 DbContext 以在您的代码中使用(这是 EFCore 的一部分,因此您可能需要先了解更多相关信息)。现在要使用 async 方法,您可以在视图中这样调用它:

<div title="@(await I(12))"></div>

同样,我会尽量避免在这样的助手中查询数据库。正如我所说,助手的方法可以在同一个视图中多次调用,所以通常我们有快速方法或使用 caching 来获取信息需要。这与另一个名为 caching 的功能有关,该功能在一个简短的答案中包含更多内容,您可以了解更多信息。

解决方法:

我的 Startup.cs 添加了:

services.AddScoped<IInfo, Info>();

services.AddTransient<IInfo, Info>(); 也有效。