在ASP.NET中转换/访问QueryString值

21

我很好奇大家在ASP.NET中是如何处理/抽象QueryString的。在我们的一些Web应用程序中,我看到这种代码遍布整个站点:

int val = 0;
if(Request.QueryString["someKey"] != null)
{
val = Convert.ToInt32(Request.QueryString["someKey"]);
}

有哪些更好的方式来处理这种恶心的东西?

7个回答

25

我倾向于将它们抽象成属性的思路。 例如:

        public int age { 
        get
        {
            if (Request.QueryString["Age"] == null)
                return 0;
            else
                return int.Parse(Request.QueryString["Age"]);                                    
        }
    }

如果你想的话,可以添加更多的验证。但是我喜欢用这种方式来包装所有的查询字符串变量。

编辑:--- 正如另一个发布者指出的那样,你必须在每个页面上创建这些属性。我的回答是不需要的。你可以在一个名为 "QueryStrings" 的类中创建这些属性。然后在你想要访问你的查询字符串的每个页面中实例化这个类,然后你只需要像这样做:

var queryStrings = new QueryStrings();
var age = queryStrings.age;

通过这种方式,您可以将访问和处理每种类型的查询变量的所有逻辑封装在一个可维护的单一位置中。

编辑2: --- 由于它是类的实例,您还可以使用依赖注入将QueryStrings类注入到您使用它的每个地方。 StructureMap 做得很好。这还允许您模拟QueryStrings类并注入它,如果您想进行自动化单元测试,则比ASP.Net的Request对象更容易模拟。


这里的额外好处是,它告诉未来的开发人员在他们第一次接触您的代码时可以从查询字符串中得到什么。 - Joel Coehoorn
是的,谢谢你注意到了。那绝对是我们的意图。 - 7wp
2
这可能会抛出异常! - user57508
1
我赞成这个解决方案。我将静态属性放在一个静态类中,可以在网站的任何地方使用,并在将字符串转换为特定类型的位置周围加上try catch。您也可以使用相同的方法访问Session或Cache对象。 - Nick
dittohole:如果您希望,在此解决方案中可以添加异常处理程序。此示例仅旨在成为该想法的“蓝图”。您可以以任何您想要的方式实现它。 - 7wp
如果您不希望查询字符串数据包含任何逗号,您还可以执行split(',')[0]以获取第一个值,以防接收到复制的查询字符串参数。 - mrd3650

8

有一件事是你没有捕获空值。你可能有一个像这样的url:“http://example.com?someKey=&anotherKey=12345”,在这种情况下,“someKey”参数值为“”(空)。您可以使用string.IsNullOrEmpty()来检查null和empty状态。

我还会更改“someKey”以存储在变量中。这样,您就不会在多个位置重复字面字符串。这使得维护更加容易。

int val = 0;
string myKey = "someKey";
if (!string.IsNullOrEmpty(Request.QueryString[myKey]))
{
    val = int.Parse(Request.QueryString[myKey]);
}

我希望你能理解这些信息! Ian

这很可能会抛出异常! - user57508
你肯定想要包括错误处理。这是理所当然的,不是吗? :) - Ian Suttle
int val = 0; string myKey = "someKey"; string strVal = HttpContext.Current.Request.QueryString[myKey]; if(!String.IsNullOrEmpty(strVal) && !int.TryParse(strVal, out val)){ val = 0; } - GFoley83

3
这是我想到的方案。它使用泛型从查询字符串中返回一个强类型值,如果参数不在查询字符串中,则返回一个可选的默认值:
/// <summary>
    /// Gets the given querystring parameter as a the specified value <see cref="Type"/>
    /// </summary>
    /// <typeparam name="T">The type to convert the querystring value to</typeparam>
    /// <param name="name">Querystring parameter name</param>
    /// <param name="defaultValue">Default value to return if parameter not found</param>
    /// <returns>The value as the specified <see cref="Type"/>, or the default value if not found</returns>
    public static T GetValueFromQueryString<T>(string name, T defaultValue) where T : struct
    {
        if (String.IsNullOrEmpty(name) || HttpContext.Current == null || HttpContext.Current.Request == null)
            return defaultValue;

        try
        {
            return (T)Convert.ChangeType(HttpContext.Current.Request.QueryString[name], typeof(T));
        }
        catch
        {
            return defaultValue;
        }
    }

    /// <summary>
    /// Gets the given querystring parameter as a the specified value <see cref="Type"/>
    /// </summary>
    /// <typeparam name="T">The type to convert the querystring value to</typeparam>
    /// <param name="name">Querystring parameter name</param>
    /// <returns>The value as the specified <see cref="Type"/>, or the types default value if not found</returns>
    public static T GetValueFromQueryString<T>(string name) where T : struct
    {
        return GetValueFromQueryString(name, default(T));
    }

自从写这篇文章以来,我已经编写了一个非常小的类库来操作查询字符串的值-请参见https://github.com/DanDiplo/QueryString-Helper

获取:字符串类型必须是非空值类型,才能在泛型中用作参数'T'。 - Drag and Drop
@PierreLebon 字符串是值类型,因此结构体通用约束对它们不起作用。但是您不需要转换它们,因为该值已经是一个字符串。自从发表这篇文章以来,我编写了一个小库-请参见https://github.com/DanDiplo/QueryString-Helper-可以帮助您。 - Dan Diplo

3

编写某种帮助方法(库)来处理它...

public static void GetInt(this NameValueCollection nvCol, string key, out int keyValue, int defaultValue)
{
    if (string.IsNullOrEmpty(nvCol[key]) || !int.TryParse(nvCol[key], out keyValue))
        keyValue = defaultValue;
}

或者类似这样的东西...


但是程序员必须知道查询字符串应该返回的预期类型(以知道调用哪个函数)。如果您像我给出的答案中所示,使用属性获取器进行包装,那么您只需要知道要查找的属性名称。智能感知将完成其余工作。 - 7wp
是的,就像程序员必须知道查询字符串的预期类型来设置属性一样。我的解决方案是停止在整个代码中重复使用令人讨厌的“if”语句,正如问题所描述的那样。之后他们对代码的处理取决于他们自己 - 嘿,把它放在一个属性里吧! - Charlino
但是一旦设置了该属性,它就完成了。之后的其他程序员不必猜测查询字符串中有什么类型的数据以及应该进行哪些特定验证。您可以将所有这些内容都封装在属性中。 - 7wp
你显然太专注于自己的答案,没有看到我的回答正在解决一个不同的问题,并且我的答案可以很好地补充你的答案。 - Charlino

1

我认为获取查询字符串的最佳方法如下:
如果未找到查询字符串,则val的值将为0

int val = 0;
int.TryParse(Request.QueryString["someKey"], out val);

1

我们一直在使用常量来将所有这些“松散”的键放在一个中心位置:

public class Constants
{
  public class QueryString
  {
    public const string PostID = "pid";
    public const string PostKey = "key";
  }
  public class Cookie
  {
    public const string UserID = "mydomain.com-userid";
  }
  public class Cache
  {
    public const string PagedPostList = "PagedPostList-{0}-{1}";
  }
  public class Context
  {
    public const string PostID = "PostID";
  }
  public class Security
  {
    public const RoleAdministrator = "Administrator";
  }
}

这样,你就可以轻松使用以下方式访问所需的常量:

public void Index()
{
  if (Request[Constants.QueryString.PostKey] == "eduncan911")
  {
    // do something
  }
}

public object GetPostsFromCache(int postID, int userID)
{
  String cacheKey = String.Format(
      Constants.Cache.PagedPostList
      , userID
      , postID);
  return Cache[cacheKey] as IList<Post>;
}

0
我同意建议使用辅助方法的发帖者(我想评论他的帖子,但还不能)。有人不同意他,而是支持创建属性,但我的回答是它不能优雅地处理检查null或无效格式等问题。如果您有辅助方法,所有逻辑都可以编写一次并集中处理。
如果您有很多页面,为每个页面添加属性可能比值得的时间更长。但这显然只是一种偏好,所以各自选择。
您可以改进其他发帖者的辅助方法的一个很酷的事情是将out参数更改为引用参数(将out更改为ref)。这样,您可以为属性设置默认值,以防未传递该属性。有时您可能需要可选参数,例如-然后您可以让它从某些默认值开始,以便在未明确传递可选参数的情况下进行处理(比单独传递默认值更容易)。您甚至可以在末尾添加一个IsRequired布尔参数,并在布尔设置为true且未传递参数时抛出异常。在许多情况下,这可能会有所帮助。

您不必在每个页面上创建属性。只需创建一个包含您希望使用的所有属性的单个类即可。然后,在您要使用它的页面中实例化该类以访问查询参数。 - 7wp
好的,这就假设每个页面上都有相同的查询字符串参数。在大型系统中,您将拥有大量不同的参数,就像您针对不同方法具有不同参数一样。似乎保持一致性是一件好事。 - Chris McElligott Park

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接