-2

上次我在这里发布问题时,每个人都为解决我的问题提供了一些很好的指导。及时前进,这是另一个。我正在尝试重做一个小型辅助工具,该工具可以根据 VirusTotal 检查 URL 和文件以获取一些基本信息。下面的代码运行良好,但锁定了 UI。有人告诉我,我应该研究一下 Rx 并喜欢阅读它,但似乎无法理解它。所以现在问题来了,设计以​​下代码以使其利用 Rx 的最佳方法是什么,以便它是异步的,并且在它做这件事时让我的 UI 独自一人。VirusTotal 还利用多级 JSON 进行响应,所以如果有人有一个很好的方法将它集成到这个中,那就更好了。

class Virustotal
{
    private string APIKey = "REMOVED";
    private string FileReportURL = "https://www.virustotal.com/vtapi/v2/file/report";
    private string URLReportURL = "http://www.virustotal.com/vtapi/v2/url/report";
    private string URLSubmitURL = "https://www.virustotal.com/vtapi/v2/url/scan";

    WebRequest theRequest;
    HttpWebResponse theResponse;
    ArrayList  theQueryData;

    public string GetFileReport(string checksum) // Gets latest report of file from VT using a hash (MD5 / SHA1 / SHA256)
    {
        this.WebPostRequest(this.FileReportURL);
        this.Add("resource", checksum);
        return this.GetResponse();
    }

    public string GetURLReport(string url) // Gets latest report of URL from VT
    {
        this.WebPostRequest(this.URLReportURL);
        this.Add("resource", url);
        this.Add("scan", "1"); //Automatically submits to VT if no result found
        return this.GetResponse();
    }

    public string SubmitURL(string url) // Submits URL to VT for insertion to scanning queue
    {
        this.WebPostRequest(this.URLSubmitURL);
        this.Add("url", url);
        return this.GetResponse();
    }

    public string SubmitFile() // Submits File to VT for insertion to scanning queue
    {
        // File Upload code needed
        return this.GetResponse();
    }

    private void WebPostRequest(string url)
    {
        theRequest = WebRequest.Create(url);
        theRequest.Method = "POST";
        theQueryData = new ArrayList();
        this.Add("apikey", APIKey);
    }

    private void Add(string key, string value)
    {
        theQueryData.Add(String.Format("{0}={1}", key, Uri.EscapeDataString(value)));
    }

    private string GetResponse()
    {
        // Set the encoding type
        theRequest.ContentType="application/x-www-form-urlencoded";

        // Build a string containing all the parameters
        string Parameters = String.Join("&",(String[]) theQueryData.ToArray(typeof(string)));
        theRequest.ContentLength = Parameters.Length;

        // We write the parameters into the request
        StreamWriter sw = new StreamWriter(theRequest.GetRequestStream());
        sw.Write(Parameters);
        sw.Close();

        // Execute the query
        theResponse =  (HttpWebResponse)theRequest.GetResponse();
        StreamReader sr = new StreamReader(theResponse.GetResponseStream());
        return sr.ReadToEnd();
    }
}
4

1 回答 1

1

您的代码写得不好,这使得异步变得更加困难 - 主要是三个类级变量。在 Rx 中编码时,您想考虑“函数式编程”而不是“OOP”——所以没有类级别的变量。

所以,我所做的是——我重新编码了GetResponse将所有状态封装到单个调用中的方法——并且我让它返回IObservable<string>而不是仅仅返回string.

公共函数现在可以这样编写:

public IObservable<string> GetFileReport(string checksum)
{
    return this.GetResponse(this.FileReportURL,
        new Dictionary<string, string>() { { "resource", checksum }, });
}

public IObservable<string> GetURLReport(string url)
{
    return this.GetResponse(this.URLReportURL,
        new Dictionary<string, string>()
            { { "resource", url }, { "scan", "1" }, });
}

public IObservable<string> SubmitURL(string url)
{
    return this.GetResponse(this.URLSubmitURL,
        new Dictionary<string, string>() { { "url", url }, });
}

public IObservable<string> SubmitFile()
{
    return this.GetResponse("UNKNOWNURL", new Dictionary<string, string>());
}

GetResponse看起来像这样:

private IObservable<string> GetResponse(
    string url,
    Dictionary<string, string> theQueryData)
{
    return Observable.Start(() =>
    {
        var theRequest = WebRequest.Create(url);
        theRequest.Method = "POST";
        theRequest.ContentType="application/x-www-form-urlencoded";

        theQueryData.Add("apikey", APIKey);

        string Parameters = String.Join("&",
            theQueryData.Select(x =>
                String.Format("{0}={1}", x.Key, x.Value)));
        theRequest.ContentLength = Parameters.Length;

        using (var sw = new StreamWriter(theRequest.GetRequestStream()))
        {
            sw.Write(Parameters);
            sw.Close();
        }

        using (var theResponse =  (HttpWebResponse)theRequest.GetResponse())
        {
            using (var sr = new StreamReader(theResponse.GetResponseStream()))
            {
                return sr.ReadToEnd();
            }
        }
    });
}

我还没有实际测试过这个 - 我没有初学者的 APIKEY - 但它应该可以正常工作。让我知道你怎么去。

于 2012-06-10T02:06:05.710 回答