【问题标题】:Converting/accessing QueryString values in ASP.NET在 ASP.NET 中转换/访问 QueryString 值
【发布时间】:2009-03-02 23:23:41
【问题描述】:

我很好奇每个人在 ASP.NET 中处理/抽象 QueryString 是做什么的。在我们的一些网络应用中,我在整个网站上看到了很多这样的内容:

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

有什么更好的方法来处理这种粗俗?

【问题讨论】:

    标签: c# .net asp.net


    【解决方案1】:

    我倾向于将它们抽象为属性的想法。 例如:

            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;
    

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

    EDIT2:--- 而且因为它是该类的一个实例,您还可以使用依赖注入将 QueryStrings 类注入到您使用它的每个地方。 StructureMap 在这方面做得很好。这还允许您模拟 QueryStrings 类并在您想要进行自动化单元测试时注入它。模拟它比 ASP.Net 的 Request 对象要容易得多。

    【讨论】:

    • 这里的额外好处是,它可以准确地告诉未来的开发人员在他们第一次坐下来使用您的代码时对查询字符串的期望。
    • 是的,感谢您注意到这一点。这绝对是意图。
    • 这很有可能会抛出异常!
    • 我赞成这个解决方案。我将静态属性放在一个静态类中,我可以在网站上的任何地方使用它,并在我将字符串转换为特定类型的地方抛出一个 try catch。您也可以使用相同的方法访问 Session 或 Cache 对象。
    • 同上:如果您愿意,可以在此解决方案中添加异常处理程序。这个例子只是为了成为这个想法的“蓝图”。你可以用任何你想要的方式来实现它。
    【解决方案2】:

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

    我还将“someKey”更改为存储在变量中。这样你就不会在多个地方重复文字字符串。它使这更容易维护。

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

    希望对你有帮助!

    伊恩

    【讨论】:

    • 这很有可能会抛出异常!
    • 您当然希望包含错误处理。这是给定的不是吗? :)
    • int val = 0; string myKey = "someKey"; string strVal = HttpContext.Current.Request.QueryString[myKey]; if(!String.IsNullOrEmpty(strVal) && !int.TryParse(strVal, out val)){ val = 0; }
    【解决方案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;
    }
    

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

    【讨论】:

    • 但是程序员必须知道查询字符串应该返回的预期类型。 (要知道要调用哪个函数)如果您使用我给出的答案中的属性获取器来包装它,那么您所需要知道的就是您所追求的属性的名称。 Intellisense 将完成剩下的工作。
    • 是的,就像程序员必须知道查询字符串的预期类型才能设置属性一样。我的解决方案是停止整个节目中重复的令人讨厌的“if”语句,如问题中所述。之后他们如何处理代码取决于他们 - 嘿,把它放在一个属性中!
    • 但是一旦设置了属性,它就完成了。之后的其他程序员将不必猜测查询字符串中的数据类型以及应该进行哪些特定验证。您可以将所有这些都包含在属性中。
    • 您显然太沉迷于自己的答案,看不到我的答案正在解决一个不同的问题,而且我的答案可以很好地补充您的答案。
    【解决方案4】:

    这就是我想出的。它使用泛型从 QueryString 中返回强类型值,如果参数不在 QueryString 中,则返回可选的默认值:

    /// <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

    【讨论】:

    • 获取:The type 'string' must be a non-nullable value type in order to use it as parameter 'T' in the generic...
    • @PierreLebon 字符串是值类型,因此 struct 泛型约束不适用于它们。但是您不需要转换它们,因为该值已经是一个字符串。自从这篇文章以来,我编写了一个小型库 - 请参阅 github.com/DanDiplo/QueryString-Helper - 这应该对您有所帮助。
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        我支持建议辅助方法的发布者(我会评论他的,但还不能评论)。其他人不同意他支持创建属性,但我对此的回答是它不能优雅地处理检查空值或无效格式等问题。如果你有辅助方法,所有这些逻辑都可以编写一次并且集中。

        如果您有很多页面,为每个页面添加属性可能会花费更多时间而不是值得。但这显然只是一种偏好,所以对每个人来说都是如此。

        您可以改进其他张贴者的辅助方法的一件很酷的事情是将 out 参数改为参考参数(将 out 更改为 ref)。这样你就可以为属性设置一个默认值,以防它没有被传递。例如,有时您可能需要可选参数——那么对于那些未显式传递可选参数的情况(比单独传入默认值更容易),您可以让它以一些默认值开头。您甚至可以在末尾添加一个 IsRequired 布尔参数,如果布尔设置为 true 并且未传递参数,则让它抛出异常。这在许多情况下会有所帮助。

        【讨论】:

        • 您不必在每个页面上都创建属性。只有一个类包含您希望使用的所有属性。然后,您可以在使用它的页面中实例化该类以访问查询参数。
        • 好吧,这假设您在每个页面上都有相同的查询字符串参数。在大型系统中,您将拥有大量不同的系统,就像您对不同的方法有不同的参数一样。似乎一致性是一件好事。
        猜你喜欢
        • 2014-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多