c# - 结合类属性参数和插入到 ViewData 的继承

标签 c# .net asp.net-mvc inheritance design-patterns

问题仅用于教育目的。

我有一个 MVC 应用程序,它有 3 个 Web Journeys,它们在许多方面相互镜像 - 这使得引入处理公共(public)部分的基类变得很方便。

我还使用了很多被放入 viewData 中的类属性 这使得在旅程之间重用 View 时变得很方便,我可以在每个旅程中插入不同的电话号码(或其他位),而无需在每个 viewModel 中继承此数据,因为每个旅程都是相同的(如图所示无法放置到母版页中)在许多不同的观点)。在生成电子邮件等时,这些常量也用在代码中。

[LayoutViewData(ContactNumber = ContactNumber, LegalType = LegalType, LegalReference = LegalReference)]
public class JourneyController : BaseJourneyController
{
    private const string ContactNumber = "0800 161 5191";
    private const string ContactNumberForPricingPage = "0800 051 3322";
    private const string ProductReference = "LS0083";
    private const string LegalReference = "conveyancing";
}


public class LayoutViewDataAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Controller.ViewData.Add("ContactNumber", this.ContactNumber);
    }
    ...
}

我正在尝试解决的问题:

有些方法在旅程中几乎相同,可以移至基础,但它们需要来自常量的值。问题是只有静态可以传递给属性,这意味着我不能简单地将它们更改为仅具有 setter/getter 的抽象属性并继续我的生活。

我的选择:

  1. 更改方法签名以将这些常量传递给方法 - 我不喜欢这样,因为必须将数据传递给基类表明实现应该在类本身中进行。

  2. 引入抽象的 Get 方法,然后返回常量以用于基类,例如。

    protected override string GetContactNumber()
    {
        return ContactNumber;
    }
    

    我不喜欢没有办法强制返回那些特定的常量,感觉有点老套,但恕我直言,这是最省力的最佳解决方案。

  3. 摆脱常量和属性,引入具有抽象属性的 BaseViewModel 类,以及为每个旅程设置值的一种机制。或者可以是 3 个已经设置了这些属性的基类。 - 不喜欢,很多替代品。

您能想出一些其他的解决方案,以最少的工作量和最少的黑客攻击来解决我的情况。

最佳答案

我认为您这里的主要问题是您将属性用于不适合的目的。属性用于将元数据添加到代码构造中。但是您正在使用它们来附加数据,这些数据通常应该是实际对象定义的一部分(作为属性 getter )。

此外,我认为您不一定非得求助于类继承才能提出适用于这种情况的设计。但如果您需要,此解决方案仍然有效。

独立接口(interface)

如果将每条数据分解成其自己的接口(interface),则可以利用一个类可以实现多个接口(interface)的事实来根据需要覆盖默认值。

public interface IContactNumber
{
    string ContactNumber { get; }
}

单独的 Action 筛选器

与其继承具有自身内置限制的 ActionFilterAttribute,不如实现 IActionFilter 以从等式中删除不必要的属性。

public class ContactNumberActionFilter : IActionFilter
{
    private readonly string defaultContactNumber;

    public ContactNumberActionFilter(string defaultContactNumber)
    {
        this.defaultContactNumber = defaultContactNumber;
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // No implementation
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var controller = filterContext.Controller;
        var provider = controller as IContactNumber;
        var contactNumber = (provider == null) ? this.defaultContactNumber : provider.ContactNumber;

        controller.ViewData.Add("ContactNumber", contactNumber);
    }
}

那么只需在全局范围内注册您的过滤器即可。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());

        // Register the action filter globally and provide a default number
        filters.Add(new ContactNumberActionFilter("0800 161 5191"));

        // TODO: Make filters for ContactNumberForPricingPage, 
        // ProductReference, and LegalReference and set their default
        // values here.
    }
}

用法

现在,如果您想覆盖默认联系电话,您只需在 Controller 中实现 IContactNumber。如果您不实现此接口(interface),将使用默认号码。

public class HomeController : Controller, IContactNumber
{
    public string ContactNumber
    {
        get { return "0800 161 5192"; }
    }

    public ActionResult Index()
    {
        return View();
    }
}

请注意,您可以还添加一种方法来打开或关闭此功能,方法是使用属性并在将 ContactNumber 添加到 之前测试其存在ViewData 如果你真的需要一个开/关开关。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ContactNumberAttribute : Attribute
{
}

关于c# - 结合类属性参数和插入到 ViewData 的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34919921/

相关文章:

c# - Linq to SQL 搜索

c# - 有没有办法从代码隐藏中读取 System.Web.Optimization 内容?

c# - 如何将 span 标签放在 Html.ActionLink 中的 anchor 标签内?

c# - 导出到 Excel .xlsx 文件

c# - 全局鼠标事件处理程序

c# - 如何在 C# 中转换键和数组的集合?

.net - Textbox.text 绑定(bind)到 MySettings 不起作用

c# - 无法在mvc项目中以所需格式呈现数据

c# - 带有列名称的 EF7 支架现有数据库 = 表名称

c# - 更改 Xamarin 中单页的导航栏颜色