MVC RouteUrl不遵守Exclude属性

时间:2011-06-19 05:55:37

标签: asp.net-mvc asp.net-mvc-2 model-binding

(我正在使用ASP.NET MVC 2.)

使用Url.RouteUrl(object)时,如何排除某些属性进入查询字符串?

具体来说,在我传递给我的View的Model对象中,我有一个字符串数组(技术上IEnumerable< string>)我想要排除。

我认为带有Exclude的Bind属性应该这样做,但它不起作用。我尝试将[Bind(Exclude = "Sizes")]放在我的课堂上,但我不断获得如下所示的网址:

的http://本地主机/尺寸= System.String []

2 个答案:

答案 0 :(得分:2)

扩展方法和反思救援!

/// <summary>
/// Add UrlHelper extension methods that construct outgoing URL's but 
/// remove route values that are excluded by the Bind attribute's 
/// Include or Exclude.  The methods to mirror are those that take an 
/// object as an argument:
///
/// public string Action(string actionName, object routeValues);
/// public string Action(string actionName, string controllerName
///                    , object routeValues);
/// public string Action(string actionName, string controllerName
///                    , object routeValues, string protocol);
///
/// public string RouteUrl(object routeValues);
/// public string RouteUrl(string routeName, object routeValues);
/// public string RouteUrl(string routeName, object routeValues
///                      , string protocol);
/// </summary>
public static class UrlHelperExtensions
{
    public static string Action(this UrlHelper helper, string actionName
                                , object routeValues, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);

        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }

        // Internally, MVC calls an overload of GenerateUrl with
        // hard-coded defaults.  Since we shouldn't know what these
        // defaults are, we call the non-extension equivalents.
        return helper.Action(actionName, routeValues);
    }

    public static string Action(this UrlHelper helper, string actionName
                                , string controllerName, object routeValues
                                , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);

        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }

        return helper.Action(actionName, controllerName, finalRouteValues);
    }

    public static string Action(this UrlHelper helper, string actionName
                                , string controllerName, object routeValues
                                , string protocol, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);

        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }

        return helper.Action(actionName, controllerName
                              , finalRouteValues, protocol);
    }

    public static string RouteUrl(this UrlHelper helper, object routeValues
                                  , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.RouteUrl(finalRouteValues);
    }

    public static string RouteUrl(this UrlHelper helper, string routeName
                                  , object routeValues, bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);
        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }
        return helper.RouteUrl(routeName, finalRouteValues);
    }

    public static string RouteUrl(this UrlHelper helper, string routeName
                                  , object routeValues, string protocol
                                  , bool onlyBoundValues)
    {
        RouteValueDictionary finalRouteValues =
             new RouteValueDictionary(routeValues);

        if (onlyBoundValues)
        {
            RemoveUnboundValues(finalRouteValues, routeValues);
        }

        return helper.RouteUrl(routeName, finalRouteValues, protocol);
    }

    /// <summary>
    /// Reflect into the routeValueObject and remove any keys from
    /// routeValues that are not bound by the Bind attribute
    /// </summary>
    private static void RemoveUnboundValues(RouteValueDictionary routeValues
                                            , object source)
    {
        if (source == null)
        {
            return;
        }

        var type = source.GetType();

        BindAttribute b = null;

        foreach (var attribute in type.GetCustomAttributes(true))
        {
            if (attribute is BindAttribute)
            {
                b = (BindAttribute)attribute;
                break;
            }
        }

        if (b == null)
        {
            return;
        }

        foreach (var property in type.GetProperties())
        {
            var propertyName = property.Name;
            if (!b.IsPropertyAllowed(propertyName))
            {
                routeValues.Remove(propertyName);
            }
        }
    }
}

答案 1 :(得分:1)

将使用匿名对象的所有属性,而AFAIK则无法排除某些属性。 [Bind]属性用于控制器操作参数,以向模型绑定器指示应从模型绑定中排除或包含的属性,但不能用于构造URL。您可能需要逐个指定所需的属性:

Url.RouteUrl(new { 
    Prop1 = Model.Prop1, 
    Prop2 = Model.Prop2, 
    action = "SomeAction",
    controller = "SomeController"
})

或仅包含ID:

Url.RouteUrl(new { 
    id = Model.Id, 
    action = "SomeAction",
    controller = "SomeController"
})

并让目标控制器操作使用此id来从某个持久数据存储中获取模型。