我有一个小程序,它从文本文件中获取链接,将这些链接传递给ImportIO的后端系统,并将结果保存为CSV。但是我在运行15,20分钟后看到了以下错误。我遇到两个例外,以先到者为准 1. System.OutOfMemoryException 要么 2. System.NUllReferenceException 然而,这两个都是我在代码中的某个地方感到我的错。我不是专家,但我尝试使用计时器,关闭文件,甚至将对象设置为null。没有工作甚至使用ArgumentNullException。 我运行了代码分析,它建议我应该忽略这个错误。
CA1001拥有一次性领域的类型应为一次性工具 可以在'ImportIO'上使用IDis,因为它会创建以下成员 IDisisable类型:'BlockingCollection>'。 Ostock Main.cs 232
我的代码如下,我不包括importIO类,它很长。我认为解决方案很简单,但我不是正确的道路。你能帮忙吗?
namespace MinimalCometLibrary
{
class Program
{
private static CountdownEvent countdownLatch;
static void Main(string[] args)
{
string[] lines = File.ReadAllLines(@"C:\Users\James\Desktop\Exper\Input_Links\Stock_links.txt");
for (int i = 0; i < lines.Length; i++)
{
string[] line = lines[i].Split(new string[] { "\t" }, StringSplitOptions.RemoveEmptyEntries);
for (int j = 0; j < line.Length; j++)
{
ImportIO io = new ImportIO("https://query.import.io", Guid.Parse("sdasd-asdasd-NoReal-3easdecb"), "NoReal=");
/* Time Starts
Stopwatch sw = new Stopwatch(); // sw cotructor
sw.Start(); // starts the stopwatch
for (int b = 0; ; b++)
{
if (b % 1000 == 0) // if in 100000th iteration (could be any other large number
// depending on how often you want the time to be checked)
{
sw.Stop(); // stop the time measurement
if (sw.ElapsedMilliseconds > 25) // check if desired period of time has elapsed
{
break; // if more than 5000 milliseconds have passed, stop looping and return
// to the existing code
}
else
{
sw.Start(); // if less than 5000 milliseconds have elapsed, continue looping
// and resume time measurement
}
}
}
//Time Ends
*/
io.Connect();
countdownLatch = new CountdownEvent(1);
// Query for tile SamsClub_Extractor, line[j]
Dictionary<String, Object> query1 = new Dictionary<string, object>();
query1.Add("input", new Dictionary<String, String>() { { "webpage/url", line[j] } });
query1.Add("connectorGuids", new List<String>() { "189f34f3-0f82-4abb-8fbc-f353f35a255a" });
io.DoQuery(query1, HandleQuery);
countdownLatch.Wait();
io.Disconnect();
}
}
Environment.Exit(0);
}
private static void HandleQuery(Query query, Dictionary<String, Object> message)
{
if (message["type"].Equals("MESSAGE"))
{
Console.WriteLine("Got data!");
string JSON = JsonConvert.SerializeObject(message["data"]);
//Deserialize to strongly typed class i.e., RootObject
RootObject obj = JsonConvert.DeserializeObject<RootObject>(JSON);
// handle null reference
if (obj == null) { throw new ArgumentNullException("PleaseKeepRunning"); }
//loop through the list and write to CSV file
foreach (Result resultsItem in obj.results)
{
Console.WriteLine(resultsItem.itemnbr + "-" + resultsItem.price +
"-" + resultsItem.product_name + "_" + obj.pageUrl);
string filePath = @"C:\Users\James\Desktop\Exper\Output_Files\StockPrice_NOW.txt";
//checking if file already exists, if not, create it:
if (!File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
fs.Close();
}
//writing to a file (appending text):
using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write))
{
using (TextWriter tw = new StreamWriter(fs))
tw.WriteLine(resultsItem.itemnbr + "\t" + resultsItem.price + "\t" + resultsItem.product_name + "\t" + resultsItem.misc +
"\t" + resultsItem.qty + "\t" + obj.pageUrl);
fs.Close();
}
//Set object to null
obj = null;
obj.results = null;
}
}
if (query.isFinished) countdownLatch.Signal();
}
}
//root Object
public class Result
{
public double price { get; set; }
public string itemnbr { get; set; }
public string product_name { get; set; }
public string qty { get; set; }
public string misc { get; set; }
}
public class RootObject
{
public List<string> cookies { get; set; }
public List<Result> results { get; set; }
public string pageUrl { get; set; }
public string connectorGuid { get; set; }
public string connectorVersionGuid { get; set; }
public int offset { get; set; }
}
请原谅我在.net上的有限知识。我完全是新手。 :) 感谢
----编辑 我按照建议使用了dispose和use,但我仍然面临错误。我看到错误异常,调试器在importIO中突出显示这行代码。
new Thread(new ThreadStart(PollQueue))。Start();
我还观察到stock.vshost.exe * 32在70MB之后的任何时候都会不断增加内存并抛出内存异常。我包含了importIO类代码
class ImportIO
{
private String host { get; set; }
private int port { get; set; }
private Guid userGuid;
private String apiKey;
private static String messagingChannel = "/messaging";
private String url;
private int msgId = 0;
private String clientId;
private Boolean isConnected;
CookieContainer cookieContainer = new CookieContainer();
Dictionary<Guid, Query> queries = new Dictionary<Guid, Query>();
private BlockingCollection<Dictionary<String, Object>> messageQueue = new BlockingCollection<Dictionary<string, object>>();
public ImportIO(String host = "http://query.import.io", Guid userGuid = default(Guid), String apiKey = null)
{
this.userGuid = userGuid;
this.apiKey = apiKey;
this.url = host + "/query/comet/";
clientId = null;
}
public void Login(String username, String password, String host = "http://api.import.io")
{
Console.WriteLine("Logging in");
String loginParams = "username=" + HttpUtility.UrlEncode(username) + "&password=" + HttpUtility.UrlEncode(password);
String searchUrl = host + "/auth/login";
HttpWebRequest loginRequest = (HttpWebRequest)WebRequest.Create(searchUrl);
loginRequest.Method = "POST";
loginRequest.ContentType = "application/x-www-form-urlencoded";
loginRequest.ContentLength = loginParams.Length;
loginRequest.CookieContainer = cookieContainer;
using (Stream dataStream = loginRequest.GetRequestStream())
{
dataStream.Write(System.Text.UTF8Encoding.UTF8.GetBytes(loginParams), 0, loginParams.Length);
HttpWebResponse loginResponse = (HttpWebResponse)loginRequest.GetResponse();
if (loginResponse.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Could not log in, code:" + loginResponse.StatusCode);
}
else
{
foreach (Cookie cookie in loginResponse.Cookies)
{
if (cookie.Name.Equals("AUTH"))
{
// Login was successful
Console.WriteLine("Login Successful");
}
}
}
}
}
public List<Dictionary<String, Object>> Request(String channel, Dictionary<String, Object> data = null, String path = "", Boolean doThrow = true)
{
Dictionary<String, Object> dataPacket = new Dictionary<String, Object>();
dataPacket.Add("channel", channel);
dataPacket.Add("connectionType", "long-polling");
dataPacket.Add("id", (msgId++).ToString());
if (this.clientId != null)
dataPacket.Add("clientId", this.clientId);
if (data != null)
{
foreach (KeyValuePair<String, Object> entry in data)
{
dataPacket.Add(entry.Key, entry.Value);
}
}
String url = this.url + path;
if (apiKey != null)
{
url += "?_user=" + HttpUtility.UrlEncode(userGuid.ToString()) + "&_apikey=" + HttpUtility.UrlEncode(apiKey);
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");
String dataJson = JsonConvert.SerializeObject(new List<Object>() { dataPacket });
request.ContentLength = dataJson.Length;
request.CookieContainer = cookieContainer;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(System.Text.UTF8Encoding.UTF8.GetBytes(dataJson), 0, dataJson.Length);
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
String responseJson = responseStream.ReadToEnd();
List<Dictionary<String, Object>> responseList = JsonConvert.DeserializeObject<List<Dictionary<String, Object>>>(responseJson);
foreach (Dictionary<String, Object> responseDict in responseList)
{
if (responseDict.ContainsKey("successful") && (bool)responseDict["successful"] != true)
{
if (doThrow)
throw new Exception("Unsucessful request");
}
if (!responseDict["channel"].Equals(messagingChannel)) continue;
if (responseDict.ContainsKey("data"))
{
messageQueue.Add(((Newtonsoft.Json.Linq.JObject)responseDict["data"]).ToObject<Dictionary<String, Object>>());
}
}
return responseList;
}
}
catch (Exception e)
{
Console.WriteLine("Error occurred {0}", e.Message);
return new List<Dictionary<String, Object>>();
}
}
}
public void Handshake()
{
Dictionary<String, Object> handshakeData = new Dictionary<String, Object>();
handshakeData.Add("version", "1.0");
handshakeData.Add("minimumVersion", "0.9");
handshakeData.Add("supportedConnectionTypes", new List<String> { "long-polling" });
handshakeData.Add("advice", new Dictionary<String, int>() { { "timeout", 60000 }, { "interval", 0 } });
List<Dictionary<String, Object>> responseList = Request("/meta/handshake", handshakeData, "handshake");
clientId = (String)responseList[0]["clientId"];
}
public void Connect()
{
if (isConnected)
{
return;
}
Handshake();
Dictionary<String, Object> subscribeData = new Dictionary<string, object>();
subscribeData.Add("subscription", messagingChannel);
Request("/meta/subscribe", subscribeData);
isConnected = true;
new Thread(new ThreadStart(Poll)).Start();
new Thread(new ThreadStart(PollQueue)).Start();
}
public void Disconnect()
{
Request("/meta/disconnect", null, "", true);
isConnected = false;
}
private void Poll()
{
while (isConnected)
{
Request("/meta/connect", null, "connect", false);
}
}
private void PollQueue()
{
while (isConnected)
{
ProcessMessage(messageQueue.Take());
}
}
private void ProcessMessage(Dictionary<String, Object> data)
{
Guid requestId = Guid.Parse((String)data["requestId"]);
Query query = queries[requestId];
query.OnMessage(data);
if (query.isFinished)
{
queries.Remove(requestId);
}
}
public void DoQuery(Dictionary<String, Object> query, QueryHandler queryHandler)
{
Guid requestId = Guid.NewGuid();
queries.Add(requestId, new Query(query, queryHandler));
query.Add("requestId", requestId);
Request("/service/query", new Dictionary<String, Object>() { { "data", query } });
}
}
答案 0 :(得分:0)
我不能说你的异常是否与它有关而没有看到完整的代码,但警告是关于“在”ImportIO中的问题,而不是在调用它的代码中(它抱怨ImportIO类没有实现IDisposable,而不是你做错了什么)
由于您使用类进行了编辑:只需在ImportIO类上实现IDisposable,这里有一个关于如何正确实现IDisposable的链接:Implementing IDisposable correctly
确保在处理ImportIO时丢弃BlockingCollection。
然后将ImportIO包装在一个使用中,警告应该消失。如果仅这一点引起了这些例外,我会感到惊讶,但这是解决警告的方法。
答案 1 :(得分:0)
尝试调用Dispose()方法,因为正如您的错误消息中所示,它是一个内存错误,因为您不断打开文件并读取它们然后将数据保存在内存中,导致您在一段时间后看到崩溃
试试这个:
if (!File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.CreateNew);
fs.Close();
fs.Dispose();
}
还可以对ImportIO类使用using(){}
using(ImportIO myIO = new ImportIO) { }