我有一个WPF C#应用程序,该应用程序使用API向Facebook和Twitter发送消息。为此,我有一个主要的静态类,可以在其中发送字符串消息和一些参数。当用户仅间歇发送通知时,该代码可以正常工作。但是,当用户一次发出多个公告时,它将不起作用。我想要的是:
我已经研究过使用BlockingCollection,但是对如何使它工作却不太幸运。
这是我当前的代码,我希望它尽可能接近此代码:
class PublishAnnouncement {
//This function is callled upon in many parts of the program and acts as a general publisher
public static void PostAnnoucment(string message, string TwAccountKey, string FbAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow) {
//First it is published to facebook
BackgroundWorker FacebookWorker = new BackgroundWorker();
FacebookWorker.DoWork += (obj, e) => FacebookDoWork(message, FbAccountKey);
FacebookWorker.RunWorkerAsync();
//Then it is published to twitter - This is where it appears to fail
BackgroundWorker TwitterWorker = new BackgroundWorker();
TwitterWorker.DoWork += (obj, e) => TwitterDoWork(message, TwAccountKey, JourneyRefID, latness, mainWindow, 0);
TwitterWorker.RunWorkerAsync();
}
private static void FacebookDoWork(string message, string FbAccountKey) {
//STAGE 1 - Facebook
//First the program will attempt to post a Facebook post.
try {
//If it is to be posted by one of the additional Facebook Pages and
//not by the default page.
var client = new RestClient("https://graph.facebook.com/v3.0/");
var request = new RestRequest("{pageId}/feed", Method.POST);
request.AddParameter("message", message); // adds to POST or URL querystring based on Method
request.AddParameter("access_token", Properties.Settings.Default.FBPageAccessToken);
request.AddUrlSegment("pageId", Properties.Settings.Default.FBPageID); // replaces matching token in request.Resource
IRestResponse response = client.Execute(request);
if (response.IsSuccessful == false) {
Console.WriteLine(response.Content);
Console.WriteLine("");
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
private static void TwitterDoWork(string message, string TwAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow, int Attempts) {
//STAGE 2 - Twitter
//Once a Facebook post has/has not been posted the program will attempt to send a tweet.
try {
Auth.SetUserCredentials(Properties.Settings.Default.TwConsumerKey, Properties.Settings.Default.TwConsumerSecret, Properties.Settings.Default.TwUserAccessToken, Properties.Settings.Default.TwUserAccessSecret);
var tweet = Tweet.PublishTweet(message);
foreach(var ID in JourneyRefID)
AddTweetID(tweet.Id, ID, latness, mainWindow);
} catch (Exception ex) {
foreach(var ID in JourneyRefID)
AddTweetID(0, ID, latness, mainWindow);
Console.WriteLine(ex.Message);
}
}
}
答案 0 :(得分:1)
我建议在公告后使用Mutex。 请在此处查看已接受的答案-使用锁示例: Usage of Mutex in c#
class PublishAnnouncement {
private static readonly object syncLock = new object();
public static void PostAnnoucment(string message, string TwAccountKey, string FbAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow) {
lock(syncLock) {
//First it is published to facebook
BackgroundWorker FacebookWorker = new BackgroundWorker();
FacebookWorker.DoWork += (obj, e) => FacebookDoWork(message, FbAccountKey);
FacebookWorker.RunWorkerAsync();
//Then it is published to twitter - This is where it appears to fail
BackgroundWorker TwitterWorker = new BackgroundWorker();
TwitterWorker.DoWork += (obj, e) => TwitterDoWork(message, TwAccountKey, JourneyRefID, latness, mainWindow, 0);
TwitterWorker.RunWorkerAsync();
//etc
}
}
}
该锁一次只允许一个线程通过,从而堆叠所有线程。请注意,我已将锁定设为静态。 (无论一次使用了多少个该类的实例,所有调用线程都只会创建并引用一个锁对象)。
如果要将锁移入后台线程:
class PublishAnnouncement {
private static readonly object syncLockForTwitter = new object();
private static readonly object syncLockForFacebook = new object();
//This function is callled upon in many parts of the program and acts as a general publisher
public static void PostAnnoucment(string message, string TwAccountKey, string FbAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow) {
//First it is published to facebook
BackgroundWorker FacebookWorker = new BackgroundWorker();
FacebookWorker.DoWork += (obj, e) => FacebookDoWork(message, FbAccountKey);
FacebookWorker.RunWorkerAsync();
//Then it is published to twitter - This is where it appears to fail
BackgroundWorker TwitterWorker = new BackgroundWorker();
TwitterWorker.DoWork += (obj, e) => TwitterDoWork(message, TwAccountKey, JourneyRefID, latness, mainWindow, 0);
TwitterWorker.RunWorkerAsync();
}
private static void FacebookDoWork(string message, string FbAccountKey) {
lock(syncLockForFacebook) {
//STAGE 1 - Facebook
//First the program will attempt to post a Facebook post.
try {
//If it is to be posted by one of the additional Facebook Pages and
//not by the default page.
var client = new RestClient("https://graph.facebook.com/v3.0/");
var request = new RestRequest("{pageId}/feed", Method.POST);
request.AddParameter("message", message); // adds to POST or URL querystring based on Method
request.AddParameter("access_token", Properties.Settings.Default.FBPageAccessToken);
request.AddUrlSegment("pageId", Properties.Settings.Default.FBPageID); // replaces matching token in request.Resource
IRestResponse response = client.Execute(request);
if (response.IsSuccessful == false) {
Console.WriteLine(response.Content);
Console.WriteLine("");
}
} catch (Exception ex) {
Console.WriteLine(ex.ToString());
}
}
}
private static void TwitterDoWork(string message, string TwAccountKey, string[] JourneyRefID, double latness, MainWindow mainWindow, int Attempts) {
lock(syncLockForTwitter) {
//STAGE 2 - Twitter
//Once a Facebook post has/has not been posted the program will attempt to send a tweet.
try {
Auth.SetUserCredentials(Properties.Settings.Default.TwConsumerKey, Properties.Settings.Default.TwConsumerSecret, Properties.Settings.Default.TwUserAccessToken, Properties.Settings.Default.TwUserAccessSecret);
var tweet = Tweet.PublishTweet(message);
foreach(var ID in JourneyRefID)
AddTweetID(tweet.Id, ID, latness, mainWindow);
} catch (Exception ex) {
foreach(var ID in JourneyRefID)
AddTweetID(0, ID, latness, mainWindow);
Console.WriteLine(ex.Message);
}
}
}
}