【问题标题】:C# Modifying multiple Dictionary Values throws errorC# 修改多个字典值会引发错误
【发布时间】:2015-09-16 12:45:39
【问题描述】:

我正在使用 HTML Agility Pack 下载一些页面,我还存储了表单中的 cookie 信息和登录信息。我遇到的问题是我正在执行 GET 操作以获取 cookie 信息和表单详细信息,因此在下一步它可以使用用户名和密码登录,然后我尝试设置用户名的值和密码输入字段,以便我可以发布到登录页面。输入字段存储在Dictionary<string,string> 中。我可以更改其中一个字典值,但之后出现错误:

“对象引用未设置为对象的实例。”。

如果我尝试更改密码然后用户名,​​则用户名会引发错误,反之亦然。这是我使用的代码:

class Main
{
private void testLogin()
        {
                BrowserSession b = new BrowserSession();
                b.Get("login.html");
                b.FormElements["email_address"] = @"email";
                b.FormElements["password"] = "password";
                string response = b.Post("index.php?main_page=login");
            }
        }
}

public class BrowserSession
{
    private bool _isPost;
    private HtmlDocument _htmlDoc;

    /// <summary>
    /// System.Net.CookieCollection. Provides a collection container for instances of Cookie class 
    /// </summary>
    public CookieCollection Cookies { get; set; }

    /// <summary>
    /// Provide a key-value-pair collection of form elements 
    /// </summary>
    public FormElementCollection FormElements { get; set; }

    /// <summary>
    /// Makes a HTTP GET request to the given URL
    /// </summary>
    public string Get(string url)
    {
        _isPost = false;
        CreateWebRequestObject().Load(url);
        return _htmlDoc.DocumentNode.InnerHtml;
    }

    /// <summary>
    /// Makes a HTTP POST request to the given URL
    /// </summary>
    public string Post(string url)
    {
        _isPost = true;
        CreateWebRequestObject().Load(url, "POST");
        return _htmlDoc.DocumentNode.InnerHtml;
    }

    /// <summary>
    /// Creates the HtmlWeb object and initializes all event handlers. 
    /// </summary>
    private HtmlWeb CreateWebRequestObject()
    {
        HtmlWeb web = new HtmlWeb();
        web.UseCookies = true;
        web.PreRequest = new HtmlWeb.PreRequestHandler(OnPreRequest);
        web.PostResponse = new HtmlWeb.PostResponseHandler(OnAfterResponse);
        web.PreHandleDocument = new HtmlWeb.PreHandleDocumentHandler(OnPreHandleDocument);
        return web;
    }

    /// <summary>
    /// Event handler for HtmlWeb.PreRequestHandler. Occurs before an HTTP request is executed.
    /// </summary>
    protected bool OnPreRequest(HttpWebRequest request)
    {
        AddCookiesTo(request);               // Add cookies that were saved from previous requests
        if (_isPost) AddPostDataTo(request); // We only need to add post data on a POST request
        return true;
    }

    /// <summary>
    /// Event handler for HtmlWeb.PostResponseHandler. Occurs after a HTTP response is received
    /// </summary>
    protected void OnAfterResponse(HttpWebRequest request, HttpWebResponse response)
    {
        SaveCookiesFrom(response); // Save cookies for subsequent requests
    }

    /// <summary>
    /// Event handler for HtmlWeb.PreHandleDocumentHandler. Occurs before a HTML document is handled
    /// </summary>
    protected void OnPreHandleDocument(HtmlDocument document)
    {
        SaveHtmlDocument(document);
    }

    /// <summary>
    /// Assembles the Post data and attaches to the request object
    /// </summary>
    private void AddPostDataTo(HttpWebRequest request)
    {
        string payload = FormElements.AssemblePostPayload();
        byte[] buff = Encoding.UTF8.GetBytes(payload.ToCharArray());
        request.ContentLength = buff.Length;
        request.ContentType = "application/x-www-form-urlencoded";
        System.IO.Stream reqStream = request.GetRequestStream();
        reqStream.Write(buff, 0, buff.Length);
    }

    /// <summary>
    /// Add cookies to the request object
    /// </summary>
    private void AddCookiesTo(HttpWebRequest request)
    {
        if (Cookies != null && Cookies.Count > 0)
        {
            request.CookieContainer.Add(Cookies);
        }
    }

    /// <summary>
    /// Saves cookies from the response object to the local CookieCollection object
    /// </summary>
    private void SaveCookiesFrom(HttpWebResponse response)
    {
        if (response.Cookies.Count > 0)
        {
            if (Cookies == null) Cookies = new CookieCollection();
            Cookies.Add(response.Cookies);
        }
    }

    /// <summary>
    /// Saves the form elements collection by parsing the HTML document
    /// </summary>
    private void SaveHtmlDocument(HtmlDocument document)
    {
        _htmlDoc = document;
        FormElements = new FormElementCollection(_htmlDoc);
    }
}

public class FormElementCollection : Dictionary<string, string>
{
    /// <summary>
    /// Constructor. Parses the HtmlDocument to get all form input elements. 
    /// </summary>
    public FormElementCollection(HtmlDocument htmlDoc)
    {
        var inputs = htmlDoc.DocumentNode.SelectSingleNode("//div[@id = 'loginDefault']").Descendants("input");
        foreach (var element in inputs)
        {
            string name = element.GetAttributeValue("name", "undefined");
            string value = element.GetAttributeValue("value", "");
            if (!name.Equals("undefined")) { Add(name, value); }
        }
    }

    /// <summary>
    /// Assembles all form elements and values to POST. Also html encodes the values.  
    /// </summary>
    public string AssemblePostPayload()
    {
        StringBuilder sb = new StringBuilder();
        foreach (var element in this)
        {
            string value = HttpUtility.UrlEncode(element.Value);
            sb.Append("&" + element.Key + "=" + value);
        }
        return sb.ToString().Substring(1);
    }
}

任何帮助将不胜感激。

【问题讨论】:

  • 作为提示,CsQuery 是 HAP 的现代替代品。我强烈建议您尝试一下,它为我节省了很多时间。至于您的实际问题,您能否进一步隔离问题?见minimal reproducible example
  • 代码中的哪一行发生了异常?
  • 为什么不使用 has-a 字典关系而不是 is-a 字典关系?您必须为必要的方法/索引器创建包装器,但在业务域建模方面更加清晰。 This link 类似,虽然它处理列表; Eric Lippert 的回答解释了我在说什么。作文

标签: c# dictionary error-handling html-agility-pack


【解决方案1】:

调试时在调用 b 构造器后放置一个断点。 你会发现FormElements property 是空的。

你需要在 BrowserSession 构造器中初始化它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2022-01-23
    • 2011-01-11
    • 2018-12-04
    • 2020-06-17
    • 2022-01-24
    相关资源
    最近更新 更多