开发者

MVC RouteUrl not honoring Exclude attribute

(I am using ASP.NET MVC 2.)

How do I exclude certain properties from going into the query string when using Url.RouteUrl(object)?

Specifically, in my Model object that is being passed to my View, I have an array of strings (technically IEnumerable<string>) I want to exclude.

I thought that the Bind attribute with Exclude was supposed to do thi开发者_JS百科s, but it doesn't work. I tried putting [Bind(Exclude = "Sizes")] on my class, but I keep getting URL's that look like this:

http://localhost/?Sizes=System.String[]


Extension methods and Reflection to the rescue!

/// <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);
            }
        }
    }
}


All the properties of the anonymous object will be used and AFAIK there is no way to exclude some. The [Bind] attribute is used on controller action arguments to indicate to the model binder properties that should be excluded or included from model binding, but not for constructing urls. You might need to specify the properties you want one by one:

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

or include only an id:

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

and have the target controller action to use this id in order to fetch the model from some persistent data store.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜