【问题标题】:Parse MVC route argument into instance将 MVC 路由参数解析为实例
【发布时间】:2016-09-24 13:06:02
【问题描述】:

是否可以通过控制器方法将路由参数从其字符串表示形式隐式转换为具有默认 Binder 的对象的实例?

假设我有一个类 BusinessObjectId,它包含两个属性并且可以从字符串转换为字符串

public class BusinessObjectId
{
    private static readonly IDictionary<bool, char> IdTypeMap = new Dictionary<bool, char> { [false] = 'c', [true] = 'd' };
    private static readonly Regex StrIdPattern = new Regex("^(?<type>[cd]{1})(?<number>\\d+)$", RegexOptions.Compiled);

    public long Id { get; set; }
    public bool IsDraft { get; set; }

    public BusinessObjectId() { }
    public BusinessObjectId(long id, bool isDraft)
    {
        Id = id;
        IsDraft = isDraft;
    }
    public BusinessObjectId(string strId)
    {
        if (string.IsNullOrEmpty(strId)) return;
        var match = StrIdPattern.Match(strId);
        if (!match.Success) throw new ArgumentException("Argument is not in correct format", nameof(strId));
        Id = long.Parse(match.Groups["number"].Value);
        IsDraft = match.Groups["type"].Value == "d";
    }

    public override string ToString()
    {
        return $"{IdTypeMap[IsDraft]}{Id}";
    }

    public static implicit operator string(BusinessObjectId busId)
    {
        return busId.ToString();
    }

    public static implicit operator BusinessObjectId(string strBussId)
    {
        return new BusinessObjectId(strBussId);
    }
}

这些操作链接被翻译成漂亮的网址:

@Html.ActionLink("xxx", "Sample1", "HomeController", new { oSampleId = new BusinessObjectId(123, false) } ... url:"/sample1/c123"

@Html.ActionLink("xxx", "Sample1", "HomeController", new { oSampleId = new BusinessObjectId(123, true) } ... url:"/sample1/d123"

然后我想像这样在控制器方法中使用参数:

public class HomeController1 : Controller
{
    [Route("sample1/{oSampleId:regex(^[cd]{1}\\d+$)}")]
    public ActionResult Sample1(BusinessObjectId oSampleId)
    {
        // oSampleId is null
        throw new NotImplementedException();
    }

    [Route("sample2/{sSampleId:regex(^[cd]{1}\\d+$)}")]
    public ActionResult Sample2(string sSampleId)
    {
        BusinessObjectId oSampleId = sSampleId;
        // oSampleId is initialized well by implicit conversion
        throw new NotImplementedException();
    }
}

方法 Sample1 无法识别传入参数并且实例 oSampleId 为空。在方法 Sample2 中,从字符串表示进行隐式转换效果很好,但我不想手动调用它。

【问题讨论】:

    标签: c# asp.net-mvc routing


    【解决方案1】:

    嗯,我找到了答案......你应该编写自定义 TypeConverter,它可以将 BusinessObjectId 类从字符串转换并用属性装饰它

    [TypeConverter(typeof(BusinessObjectIdConverter))]
    public class BusinessObjectId
    { ... }
    
    public class BusinessObjectIdConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string);
        }
    
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            return new BusinessObjectId((string)value);
        }
    }
    

    从现在开始,您可以在控制器方法中使用 BusinessObjectId 作为参数,它将像魅力一样被初始化:-)

    public class HomeController1 : Controller
    {
        [Route("sample1/{oSampleId:regex(^[cd]{1}\\d+$)}")]
        public ActionResult Sample1(BusinessObjectId oSampleId)
        {
            // TODO: oSampleId is successfully parsed from it's string representations
        }
    }
    

    【讨论】:

    • 请注意,另一种选择是创建您自己的value provider。虽然,我认为您的解决方案更适合这种特殊情况。
    猜你喜欢
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多