0

有没有办法在 MVC3 中创建一个仅包含控制器名称但不包含其参数的 URL 我做了@url.Action("action","controller",the model)一个我希望用户看到的操作;'/controller/action' 不是 '/controller/action?....&..&..' 我不知道我该怎么做。

4

1 回答 1

1

您可以使用 MVC 控制库。我做了类似的事情而不需要 contrlib

public static class UrlExtensions
{
    public static string Action<TController>(this UrlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
    {
        return BuildUrlFromExpression(urlHelper.RequestContext, urlHelper.RouteCollection, expression);
    }

    public static string ActionWithParameters<TController>(this UrlHelper urlHelper, Expression<Action<TController>> expression) where TController : Controller
    {
        return BuildUrlFromExpressionWithParameters(urlHelper.RequestContext, urlHelper.RouteCollection, expression);
    }

    public static RedirectToRouteResult Redirect<TController>(this TController controller, Expression<Action<TController>> expression) where TController : Controller
    {
        var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpressionWithParameters(expression);

        return new RedirectToRouteResult(valuesFromExpression);

    }

    private static string BuildUrlFromExpression<TController>(RequestContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller
    {
        var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpression(action);
        var virtualPathForArea = RouteCollectionExtensions.GetVirtualPathForArea(routeCollection, context, valuesFromExpression);
        if (virtualPathForArea != null)
            return virtualPathForArea.VirtualPath;
        return null;
    }

    private static string BuildUrlFromExpressionWithParameters<TController>(RequestContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller
    {
        var valuesFromExpression = ExpressionHelper.GetRouteValuesFromExpressionWithParameters(action);
        var virtualPathForArea = RouteCollectionExtensions.GetVirtualPathForArea(routeCollection, context, valuesFromExpression);
        if (virtualPathForArea != null)
            return virtualPathForArea.VirtualPath;
        return null;
    }
}

public static class ExpressionHelper
{
    public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller
    {
        MethodCallExpression call;
        return GetRouteValuesFromExpression(action, out call);
    }

    public static RouteValueDictionary GetRouteValuesFromExpressionWithParameters<TController>(Expression<Action<TController>> action) where TController : Controller
    {
        MethodCallExpression call;
        var rvd = GetRouteValuesFromExpression(action, out call);
        AddParameterValuesFromExpressionToDictionary(rvd, call);
        return rvd;
    }

    private static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action, out MethodCallExpression call) where TController : Controller
    {
        if (action == null)
            throw new ArgumentNullException("action");
        call = action.Body as MethodCallExpression;
        if (call == null)
            throw new ArgumentException("MustBeMethodCall", "action");
        string name = typeof(TController).Name;
        if (!name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
            throw new ArgumentException("TargetMustEndInController", "action");
        string str = name.Substring(0, name.Length - "Controller".Length);
        if (str.Length == 0)
            throw new ArgumentException("CannotRouteToController", "action");
        string targetActionName = GetTargetActionName(call.Method);
        var rvd = new RouteValueDictionary();
        rvd.Add("Controller", (object)str);
        rvd.Add("Action", (object)targetActionName);
        var linkAreaAttribute = typeof(TController).GetCustomAttributes(typeof(ActionLinkAreaAttribute), true).FirstOrDefault() as ActionLinkAreaAttribute;
        if (linkAreaAttribute != null)
        {
            string area = linkAreaAttribute.Area;
            rvd.Add("Area", (object)area);
        }
        return rvd;
    }

    public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
            return GetInputName((MethodCallExpression)expression.Body).Substring(expression.Parameters[0].Name.Length + 1);
        else
            return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
    }

    public static PropertyInfo GetPropertyInfo<TModel, TValue>(Expression<Func<TModel, TValue>> expression)
    {
        var member = expression.Body as MemberExpression;
        if (member == null)
            return null;
        var propInfo = member.Member as PropertyInfo;

        return propInfo;
    }


    private static string GetInputName(MethodCallExpression expression)
    {
        var expression1 = expression.Object as MethodCallExpression;
        if (expression1 != null)
            return GetInputName(expression1);
        else
            return expression.Object.ToString();
    }

    private static string GetTargetActionName(MethodInfo methodInfo)
    {
        if (methodInfo == null) throw new ArgumentNullException("methodInfo");
        var name = methodInfo.Name;
        if (methodInfo.IsDefined(typeof (NonActionAttribute), true))
        {
            throw new InvalidOperationException(string.Format(Helpers.MyFormat, "CannotCallNonAction {0}", name));
        }

        var actionNameAttribute = methodInfo.GetCustomAttributes(typeof (ActionNameAttribute), true).OfType<ActionNameAttribute>().FirstOrDefault();
        if (actionNameAttribute != null)
            return actionNameAttribute.Name;
        if (methodInfo.DeclaringType.IsSubclassOf(typeof (AsyncController)))
        {
            if (name.EndsWith("Async", StringComparison.OrdinalIgnoreCase))
                return name.Substring(0, name.Length - "Async".Length);
            if (name.EndsWith("Completed", StringComparison.OrdinalIgnoreCase))
                throw new InvalidOperationException(string.Format(Helpers.MyFormat, "CannotCallCompletedMethod: {0}", name));
        }
        return name;
    }

    private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary rvd, MethodCallExpression call)
    {
        var parameters = call.Method.GetParameters();
        if (parameters.Length <= 0)
            return;
        for (int index = 0; index < parameters.Length; ++index)
        {
            var expression = call.Arguments[index];
            var constantExpression = expression as ConstantExpression;
            var obj = constantExpression == null ? CachedExpressionCompiler.Evaluate(expression) : constantExpression.Value;
            rvd.Add(parameters[index].Name, obj);
        }
    }
}

从您的角度来看,您现在可以这样做,必须传递默认值才能使 LINQ 表达式起作用,但它们不会被呈现

@(Url.Action<MyController>(x => x.MethodName(null, 0, 0)))
于 2012-04-26T07:42:06.590 回答