【问题标题】:How to design InfoHelper for html title attribute如何为 html 标题属性设计 InfoHelper
【发布时间】:2021-05-31 08:42:33
【问题描述】:

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

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

其中 12 是 HelpInfo 记录的示例 ID,@I 应该是获取相应 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&lt;TModel&gt;

在我使用&lt;div title='@(await I(12))'&gt;Test&lt;/div&gt;的视图中

当我加载视图时,我得到了

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

任何帮助解决问题的人都将不胜感激。

【问题讨论】:

    标签: c# html asp.net-mvc asp.net-core razor


    【解决方案1】:

    解决方案

    我在 Startup.cs 中添加了:

    services.AddScoped&lt;IInfo, Info&gt;();

    services.AddTransient&lt;IInfo, Info&gt;(); 也可以。

    【讨论】:

      【解决方案2】:

      据我了解,您似乎想要@Html@Url 之类的东西,默认PageRazorPage 支持它们。这只是基本页面公开的自定义属性。因此,在您的情况下,您需要一个自定义视图(对于 mvc)或一个自定义页面(对于剃刀页面)。以下是用于 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 方法返回 string,您也可以使其返回 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 的功能有关,该功能需要在一个简短的答案中提供更多信息,您可以了解更多信息。

      【讨论】:

      • 我尝试了你的方法,但我被困在:受保护的 IInfo Info { get; } = Context.RequestServices.GetRequiredService();我在 Context 下得到红色波浪线和错误:字段初始化程序无法引用非静态、方法或属性“Razor.Page.Context”。
      • @Manu 抱歉,请参阅更新。如果您的环境不支持 =&gt;,请尝试将其声明为 public get private set(不是我之前写的只读)。
      • 现在有:受保护的 IInfo 信息 => Context.RequestServices.GetRequiredService();没有错误出现。但是我仍然需要更多帮助,比如将 HelpInfo 放入返回字符串中。当我从公共字符串 I(int code) 方法中的 dbContext 获取 HelpInfo 时,我是否正确?不然呢?
      • @Manu 可以注入服务以从 DbContext 查询数据,请参阅我的回答中更新的 NOTE 部分,一般来说我们应避免缓慢查询以确保性能可以接受。
      • @Manu 是的,实际上您需要的所有数据(尤其是业务数据)都应该被提取到视图模型中。这是 MVC 的严格规则。但是我们通过在页面/视图类中支持数据源(包括对 DI 的支持)来稍微放松一下。这在某些情况下可能很方便,但无论如何数据访问应该很快,我们可以轻松控制加载到视图模型中的内容,但不能控制分散在视图中的其他内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多