Asp.net mvc 如何在控制器操作上使用可选的通用参数?

Asp.net mvc 如何在控制器操作上使用可选的通用参数?,asp.net-mvc,generics,parameters,asp.net-mvc-controller,Asp.net Mvc,Generics,Parameters,Asp.net Mvc Controller,我正在使用一个用于各种实体的BaseController。它们可能有int或string主键,由表示 例如: [HttpGet] public ActionResult Create(TPk id) { return View(); } 在我尝试使用TPk作为可选参数之前,一切都很好 [HttpGet] public ActionResult Create(TPk id = default(TPk)) { return View(); } “可选”部分似乎不起作用 所以/co

我正在使用一个用于各种实体的BaseController。它们可能有
int
string
主键,由
表示

例如:

[HttpGet]
public ActionResult Create(TPk id)
{
    return View();
}
在我尝试使用
TPk
作为可选参数之前,一切都很好

[HttpGet]
public ActionResult Create(TPk id = default(TPk))
{
    return View();
}
“可选”部分似乎不起作用

所以
/controller/create/2
可以,但是
/controller/create
给了我以下错误:

参数字典包含方法“System.Web.Mvc.ActionResult Create(Int32)”的非null类型“System.Int32”的参数“id”的null条目

该可选选项与
int
string
id配合使用效果良好。我可以调用
/controller/create/2
/controller/create

但是使用泛型类型参数TPk,无参数路由不再工作


我试过的 我已尝试将
TPk
参数设置为空,但无法编译:

类型“TPk”必须是不可为Null的值类型,才能将其用作泛型类型或方法“nullable”中的参数“T”


我已尝试根据-no-joy将参数名称从
id
更改为
altId


我尝试过以完全相同的方式调用相同的方法,但使用了非泛型参数。例如:

public virtual async Task<ActionResult> Create(int id = default(int))
公共虚拟异步任务创建(int id=default(int)) 这很有效


我尝试创建一个简单的新项目来隔离此代码。(如下所示)。这仍然会给无参数版本带来问题


简单代码测试 控制器

public abstract class BaseController<TPk> : Controller
{
    public ActionResult Create(TPk id = default(TPk))
    {
        return View();
    }
}


public class NewsController : BaseController<int>
{

}
公共抽象类BaseController:控制器
{
公共操作结果创建(TPk id=默认值(TPk))
{
返回视图();
}
}
公共类NewsController:BaseController
{
}
实体类

public class BaseDataModel<TPk>
{
    public TPk Id { get; set; }
    public string Title { get; set; }
}

public class PageDataModel : BaseDataModel<string>
{
    public string Content { get; set; }
}

public class NewsDataModel : BaseDataModel<int>
{
    public DateTime Date { get; set; }
}
公共类BaseDataModel
{
公共TPk Id{get;set;}
公共字符串标题{get;set;}
}
公共类PageDataModel:BaseDataModel
{
公共字符串内容{get;set;}
}
公共类NewsDataModel:BaseDataModel
{
公共日期时间日期{get;set;}
}

Asp.net约定主要基于反射。所以这可以解释这种行为。我还没有测试它是否真的不起作用,但我确信在这种状态下,您已经尝试创建一个新项目(POC)来排除任何自定义代码

也许可以通过深入研究路由(方法选择)和ModelBinder源代码来修复它

我只想创建一个不同的
DuplicateRecord
操作

如果您不理解没有此注释的方法,这是一个很好的指示,您当前的代码可能有异味。(你在做同样的事情):

将共享内容提取到另一个方法(甚至可能是一个服务类),并为每个差异使用一个单独的方法


这就是说,通用CrudController的想法很可爱,几年前我自己也尝试过。但在尝试这样做的过程中,我引入了各种通用参数、策略模式、事件委托,以使所有可能性成为可能

  • 如果需要加入,会发生什么
  • 如果您需要交易,会发生什么
  • 如何处理错误
  • 如果crud逻辑需要1,2,3。。。决定要做什么的其他参数
  • 软删除/硬删除
  • 级联删除/限制删除
  • 如果你
我已经写了这么多的代码,恢复到好的旧的非泛型代码是件好事。如果抽象到一个服务中,ActionMethods实际上不需要变大

public async Task<IActionResult> CreateProduct(CancellationToken ct, ProductCreateModel model)
{
    var result = await _productService.CreateAsync(model, ct);    
    //create response with some helpers... probably some ActionFilters
}
公共异步任务CreateProduct(CancellationToken ct,ProductCreateModel模型)
{
var result=await\u productService.CreateAsync(模型,ct);
//使用一些助手创建响应…可能是一些ActionFilter
}

泛型可以在一个简单的crud映射中进行压缩,其中每个视图都有一个实体,但它的伸缩性不是很好。所以,仔细想想你真正想要什么;)

谢谢!我可能会使用
DuplicateRecord
操作,但如果可能的话,我想了解为什么这不起作用。如果我找到答案,我会把它贴出来。。。我很感激通用积垢警告,我知道这是真的。这是我对该模式的第三次或第四次迭代,我刚刚解决了这些问题,创建了一个我可以使用的解决方案。“Asp.net约定在很大程度上基于反射。因此,这可能解释了这种行为。”你能在此基础上进行扩展吗?不确定,我应该扩展什么具体内容。这也许可以解释这种行为,我的意思是,反射可以引入人们意想不到的各种错误。例如,在这种情况下,泛型的处理似乎不正确。请看下面的示例。代码的一半是反射。
public async Task<IActionResult> CreateProduct(CancellationToken ct, ProductCreateModel model)
{
    var result = await _productService.CreateAsync(model, ct);    
    //create response with some helpers... probably some ActionFilters
}