将MVC路由参数解析为实例

时间:2016-05-26 13:31:08

标签: c# asp.net-mvc routing

是否可以通过控制器方法将路由参数从它的字符串表示隐式转换为具有默认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(&#34; xxx&#34;,&#34; Sample1&#34;,&#34; HomeController&#34;,new {oSampleId = new BusinessObjectId(123,false)} ...的网址:&#34; / SAMPLE1 / C123&#34;

@ Html.ActionLink(&#34; xxx&#34;,&#34; Sample1&#34;,&#34; HomeController&#34;,new {oSampleId = new BusinessObjectId(123,true)} ...的网址:&#34; / SAMPLE1 / D123&#34;

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

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为null。在方法Sample2中,字符串表示的隐式转换效果很好,但我不想手动调用它。

1 个答案:

答案 0 :(得分: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
    }
}