在ASP.NET中验证和解析url参数

时间:2012-12-28 06:28:33

标签: c# asp.net oop validation refactoring

我维护一个遗留的WebForms应用程序,其中一个页面只提供GET请求并使用许多查询字符串参数。这项工作在代码隐藏中完成,并进行了大量此类检查和转换。

protected override void OnLoad(EventArgs e)
{
    string error = string.Empty;

    string stringParam = Request.Params["stringParam"];
    if (!String.IsNullOrEmpty(stringParam))
    {
        error = "No parameter";
        goto LoadError;
    }

    Guid? someId = null;
    try
    {
        someId = new Guid(Request.Params["guidParam"]);
    }
    catch (Exception){}
    if (!someId.HasValue)
    {
        error = "No valid id";
        goto LoadError;
    }

    // parameter checks continue on

LoadError:
    log.ErrorFormat("Error loading page: {0}", error);
    // display error page
}

我想创建一个可测试的类,它封装了这个解析和验证,并将其移出代码隐藏。任何人都可以推荐一些方法和/或例子吗?

2 个答案:

答案 0 :(得分:2)

作为第一个重要步骤,我可能会创建某种形式的映射器/转换器对象,如下所示:

class SpecificPageRequestMapper 
{
    public SpecificPageRequest Map(NameValueCollection parameters)
    {
        var request = new SpecificPageRequest();
        string stringParam = parameters["stringParam"];
        if (String.IsNullOrEmpty(stringParam))
        {
            throw new SpecificPageRequestMappingException("No parameter");
        }

        request.StringParam = stringParam;

        // more parameters

        ...

        return request;
    }
}

class SpecificPageRequest
{
    public string StringParam { get; set; }
    // more parameters...
}

然后你的OnLoad看起来像这样:

protected override void OnLoad(EventArgs e)
{  
    try
    {
        var requestObject = requestMapper.Map(Request.Params);
        stringParam = requestObject.StringParam;
        // so on, so forth. Unpack them to the class variables first.
        // Eventually, just use the request object everywhere, maybe.
    }
    catch(SpecificPageRequestMappingException ex)
    {
        log.ErrorFormat("Error loading page: {0}", ex.Message);
        // display error page
    }
}

我省略了我创建的特定异常的代码,并假设您在页面后面的某处实例化了一个映射器。

测试这个新对象应该是微不足道的;在传递给Map的集合上设置参数,然后断言请求对象上的正确参数具有您期望的值。您甚至可以通过检查它是否在正确的情况下抛出异常来测试日志消息。

答案 1 :(得分:1)

假设您可能有许多此类页面使用此类参数解析,请首先在NamedValueCollection上创建一个具有扩展方法的简单静态类。例如,

static class Parser
{    
    public static int? ParseInt(this NamedValueCollection params, string name)
    {
        var textVal = params[name];
        int result = 0;
        if (string.IsNullOrEmpty(textVal) || !int.TryParse(textVal, out result))
        {
            return null;
        }
        return result;
    }

   public static bool TryParseInt(this NamedValueCollection params, string name, out int result)
    {
        result = 0;
        var textVal = params[name];
        if (string.IsNullOrEmpty(textVal))
            return false;
        return int.TryParse(textVal, out result);
    }

    // ...    
}

按如下方式使用

int someId = -1;
if (!Request.Params.TryParseInt("SomeId", out someId))
{
   // error
}

下一步是编写特定于页面的解析器类。例如,

public class MyPageParser
{
    public int? SomeId { get; private set; } 
    /// ...

    public IEnumerable<string> Parse(NamedValueCollection params)
    {
        var errors = new List<string>();
        int someId = -1;
        if (!params.TryParseInt("SomeId", out someId))
        {
            errors.Add("Some id not present");
            this.SomeId = null;
        }
        this.SomeId = someId;

        // ...  
    }
}