This may be a very basic problem, but I haven't found any answer for it yet. I'm using Exchange Web Services in a Windows service to monitor new mails sent to our Exchange 2010 server with a pull subscription. It's working all fine and dandy, but the problems is if the server is not available (such as after a power outage), then the subscription times out, and the Windows service needs to be restarted. Is there a way to renew the subscription after a timeout, or to pull EvenType.Status events?
Here's my code so far:
ExchangeService service;
PullSubscription subscriptionInbox;
private void SetService()
{
service = new ExchangeService(ExchangeVersion.Exchange2010);
service.Url = new Uri("myurl");
service.Credentials = new WebCredentials(emailAddress, pass);
}
private void SetSubscription()
{
if (service == null)
{
SetService();
}
subscriptionInbox = service.SubscribeToPullNotifications(
new FolderId[] { WellKnownFolderName.Inbox },
5,
null,
EventType.NewMail, EventType.Modified);
}
private void DoStuff(object sender, EventArgs e)
{
GetEventsResults eventsInbox = subscriptionInbox.GetEvents();
EmailMessage message;
foreach (ItemEvent itemEvent in eventsInbox.ItemEvents)
{
//Do Stuff
}
}
Any ideas how I could go on with this?
When you lose a subscription, it's best to create a new subscription - and not try to recover the interim data. You can resubscribe with the old watermark, but it's cost prohibitive. This link provides some additional context about recovering notifications related to lost subscriptions: http://msdn.microsoft.com/en-us/library/office/dn458788(v=exchg.150).aspx#bk_recover. You may also want to view this Channel 9 video, which discusses recovery from lost subscriptions: http://channel9.msdn.com/Events/Open-Specifications-Plugfests/Windows-Identity-and-Exchange-Protocols-Plugfest-2012/Exchange-Web-Services-Best-Practices-Part-2.
Related
I am trying to receive all messages for a given subscription to a Service Bus Topic, but for the context of this app I do not want them dead lettered at this time, I just want to view them and leave them on the subscription. Despite instantiating the Client as
SubscriptionClient sc = SubscriptionClient.CreateFromConnectionString(connectionString, sub.topicName, sub.subscriptionName, ReceiveMode.PeekLock);
and making sure that I am using message.Abandon() rather than message.Complete() the message always gets Dead-lettered after accessing the message. I also have options.AutoComplete set to false
full method code below:
public List<ServiceBusMessage> RetrieveSubscriptionMessages(Subscription sub) {
ServiceBusMessage sbm;
List<ServiceBusMessage> list = new List<ServiceBusMessage>();
String connectionString = ConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"].ToString();
SubscriptionClient sc = SubscriptionClient.CreateFromConnectionString(connectionString, sub.topicName, sub.subscriptionName, ReceiveMode.PeekLock);
OnMessageOptions options = new OnMessageOptions();
options.AutoComplete = false;
sc.OnMessage((message) => {
try {
sbm = new ServiceBusMessage() {
topicName = sub.topicName,
messageText = message.GetBody<String>()
};
list.Add(sbm);
message.Abandon();
}
catch (Exception) {
message.Abandon();
throw;
}
}, options);
return list;
}
Am I missing something ? Or is there an issue with auto dead-lettering with the onMessage() method?
Thanks !
When a message is abandoned the service bus will immediately make it available for re-delivery to any subscriber of the topic.
If you are trying to configure a multicast mechanism in which multiple listeners all receive the same message, then understand that all listeners on a given subscription will be competing for the same message. In order for every listener to receive its own copy of the message, then simply create a unique subscription to the topic for each listener.
If your intent is to delay re-delivery of the abandoned message, you might look at the SO question: What's the proper way to abandon an Azure SB Message so that it becomes visible again in the future in a way I can control?
I have a WCF Service working via named pipes that is receiving data from ASP.NET MVC application:
[ServiceContract]
public interface IEmailProcessor
{
[OperationContract(AsyncPattern = true)]
void SendEmails(string subject, string body, string from, string to);
}
Service gets subject, body, sender and recipients of an email. Then it puts an email together and send via SMTP.
Client (MVC applicataion) is sending several emails at once, so I would like the service itself to work asynchronously (client just invokes SendEmails method few times and then the WCF Server takes care of the rest). But my email server sometimes refuses to send email because of greylisting of new email addresses. That's why I would like the WCF Server to also queue those email and try to send them one by one (retry few times if the error occurs).
I've read several topics on WCF async nad MSMQ methods, but what is the best approach in my situation? Should I create two WCF Services (client-server & server-server)? Or maybe use multi-threading? It's also important for me to not use any built-in SMTP solution because I would like to expand my Service to handle other messages not only emails.
For exactly the same requirement I've made this whole Email solution for my self however I did not use the MSMQ queue.
following are the steps
Create Asynchronous WCF web service
Use Task await async technique to run the send email thread inside service using task.run(()=>AsyncSendEmail)
skip through on all smptpexception on try catch and run sp to update table field
isEmailSent= false
in case of error
subscribe the web servive through client "yourwebapplication"
invoke service by doing task.factory.startNew(()=> proxy.sendEmail(paramters))
create a simple windows task scheduler task to invoke to run service on scheduled time period to retry sending emails Simple Window Task Schedular
To read no deliver, failure email Emails from your exchange account I used third party service component Admin System Software and update table fields isDelivered=No , ErrorDescription=errorDesc
Hope this solution helps you..
Shaz
I followed zaitsman's suggestion and created queue inside the service using ConcurrentQueue. I also used this example of creating new Thread: http://msdn.microsoft.com/en-us/library/7a2f3ay4%28v=vs.80%29.aspx
I added new Thread to my WCF Server:
var thread = new Thread(EmailThread.Instace.DoWork);
thread.Start();
And then SendEmails method in my Service uses Enqueue to add msg to the ConcurrentQueue.
public void SendEmails(string from, string to, string subject, string body)
{
var msg = new MailMessage(from, to, subject, body)
{
IsBodyHtml = true,
BodyEncoding = Encoding.UTF8,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
};
EmailThread.Instace.Messages.Enqueue(msg);
}
And here is EmailThread class that is doing it's work in the background (ie. accepting new emails to the queue and sequentially dequeuing them.
internal class EmailThread
{
//Ensure that only one instance of EmailThread can exist
private static readonly EmailThread Instance = new EmailThread();
public static EmailThread Instace { get { return Instance; } }
//Here is our Queue
public ConcurrentQueue<MailMessage> Messages { get; private set; }
private EmailThread()
{
Messages = new ConcurrentQueue<MailMessage>();
}
// This method is called when the thread is started and repeated once a 10 seconds
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("email sender thread: working...");
if (!Messages.IsEmpty)
{
//define SMTP credentials here
var smtp = new SmtpClient()
var failed = new Queue<MailMessage>();
MailMessage message;
while (Messages.TryDequeue(out message))
{
try
{
smtp.Send(message);
Console.WriteLine("email sender thread: successfully sent email...");
}
catch (SmtpException)
{
//Enqueue again if failed
failed.Enqueue(message);
Console.WriteLine("email sender thread: error sending email, enqueuing...");
}
}
foreach (var mailMessage in failed)
{
Messages.Enqueue(mailMessage);
}
smtp.Dispose();
}
Thread.Sleep(10000);
}
Console.WriteLine("email sender thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
I have a project where I need to create a windows service that, when instructed via a command, will perform various tasks. This server would run on multiple servers and would effectively perform the same kind of tasks when requested.
For example, I would like to have a Web API service that listens for requests from the servers.
The service running on the server would send a query to Web API every 25 secs or so and pass to it its SERVERNAME. The Web API logic will then look up the SERVERNAME and look for any status updates for various tasks... I.E., if a status for a DELETE command is a 1, the service would delete the folder containing log files... if a status for a ZIP command is a 1, the service would zip the folder containing log files and FTP them to a centralized location.
This concept seems simple enough, and I think I need a nudge to tell me if this sounds like a good design. I'm thinking of using .NET 4.5 for the Windows Service, so that I can use the HttpClient object and, of course, .NET 4.5 for the Web API/MVC project.
Can someone please get me started on what a basic Web API woudld look like provide status updates to the Windows services that are running and issue commands to them...
I'm thinking of having a simple MVC website that folks will have a list of servers (maybe based on a simple XML file or something) that they can click various radio buttons to turn on "DELETE", "ZIP" or whatever, to trigger the task on the service.
I do something similar. I have a main Web API (a Windows Service) that drives my application and has a resource called /Heartbeat.
I also have a second Windows Service that has a timer fire every 30 seconds. Each time the timer fires it calls POST /heartbeat. When the heartbeat request is handled, it goes looking for tasks that have been scheduled.
The advantage of this approach is that the service makes the hearbeat request is extremely simple and never has to be updated. All the logic relating to what happens on a heartbeat is in the main service.
The guts of the service are this. It's old code so it is still using HttpWebRequest instead of HttpClient, but that's trivial to change.
public partial class HeartbeatService : ServiceBase {
readonly Timer _Timer = new System.Timers.Timer();
private string _heartbeatTarget;
public HeartbeatService() {
Trace.TraceInformation("Initializing Heartbeat Service");
InitializeComponent();
this.ServiceName = "TavisHeartbeat";
}
protected override void OnStart(string[] args) {
Trace.TraceInformation("Starting...");
_Timer.Enabled = true;
_Timer.Interval = Properties.Settings.Default.IntervalMinutes * 1000 * 60;
_Timer.Elapsed += new ElapsedEventHandler(_Timer_Elapsed);
_heartbeatTarget = Properties.Settings.Default.TargetUrl;
}
protected override void OnStop() {
_Timer.Enabled = false;
}
private void _Timer_Elapsed(object sender, ElapsedEventArgs e) {
Trace.TraceInformation("Heartbeat event triggered");
try {
var httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(_heartbeatTarget);
httpWebRequest.ContentLength = 0;
httpWebRequest.Method = "POST";
var response = (HttpWebResponse)httpWebRequest.GetResponse();
Trace.TraceInformation("Http Response : " + response.StatusCode + " " + response.StatusDescription);
} catch (Exception ex) {
string errorMessage = ex.Message;
while (ex.InnerException != null) {
errorMessage = errorMessage + Environment.NewLine + ex.InnerException.Message;
ex = ex.InnerException;
}
Trace.TraceError(errorMessage);
}
}
}
You can do it with ServiceController.ExecuteCommand() method from .NET.
With the method you can sand custom command to windows' service.
Then in your service you need to implement ServiceBase.OnCustomCommand() to serve incomming custom command event in service.
const int SmartRestart = 8;
...
//APPLICATION TO SEND COMMAND
service.ExecuteCommand(SmartRestart);
...
//SERVICE
protected override void OnCustomCommand(int command)
{
if (command == SmartRestart)
{
// ...
}
}
Simply I would like to receive a notification every time someone added a new appointment or made any changes on what he/she has.
The only way I know how to do it , is by using
service.SubscribeToStreamingNotifications
but the problem here that it only listens to the account that the service is bound to like in this way
var service = new ExchangeService(ExchangeVersion.Exchange2010_SP2)
{
Credentials = new WebCredentials(userName, password)
};
service.SubscribeToStreamingNotifications(new FolderId[]
{
WellKnownFolderName.Calendar
}, EventType.FreeBusyChanged, EventType.Deleted);
I have solved this problem by creating a list of services each service is bounded to different user and the application should listen to each of them.
The problem with this way is that I need to have the password of each account I wont to listen to its events, which is not possible in real world.
so is there any way to deal with that ?
I have solved this problem, by creating a list of services, all the services are a clone of the main ExchangeService, with the same credentials for the admin account, but they are impersonated to the other accounts.
NOTE: You need to setup the server so it allows impersonation.
private void ImpersonateUsers(ICollection<string> userSmtps)
{
if (userSmtps != null)
if (userSmtps.Count > 0)
{
foreach (var userSmtp in userSmtps)
{
if (_services.ContainsKey(userSmtp)) continue;
var newService = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
try
{
var serviceCred = ((System.Net.NetworkCredential)(((WebCredentials)(_services.First().Value.Credentials)).Credentials));
newService.Credentials = new WebCredentials(serviceCred.UserName, serviceCred.Password, serviceCred.Domain);
newService.AutodiscoverUrl(serviceCred.UserName + "#" + serviceCred.Domain, RedirectionUrlValidationCallback);
newService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, userSmtp);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
_services.Add(userSmtp, newService);
}
}
}
Where userSmtps is a list of the email addresses I want to impersonate and _services is the dictionary of services where the first member is the main service.
you will have to create a service instance per user. There is no way to subscribe to other users folder.
But instead of StreamingNotifications you can use Pull and Push-Subscriptions too.
Something like this:
List<FolderId> folders = new List<FolderId>();
folders.Add(new FolderId(WellKnownFolderName.Calendar));
PullSubscription subscription = = service.SubscribeToPullNotifications(folders, 1440, watermark, EventType.Created, EventType.Deleted, EventType.Modified, EventType.Moved, EventType.NewMail);
Some time later....
GetEventsResults currentevents = m_subscription .GetEvents();
I'm using the ExchangeService WebService API (Microsoft.Exchange.WebServices.Data) but I cannot find any Close or Dispose method.
Is it not neccessary to close the connection somehow?
My method looks like this:
public void CheckMails()
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
IMAPCredentials creds = new IMAPCredentials();
service.Credentials = new NetworkCredential(creds.User, creds.Pass, creds.Domain);
service.AutodiscoverUrl(creds.User + "#example.com");
// not the real code from here on but you'll get the idea...
// var emails = service.FindItems();
// emails[0].Load();
// emails[0].Attachments[0].Load();
// ...
}
There is no Close/Dispose method on the ExchangeService class because the class does not maintain a connection to the web services. Instead a new HTTP connection is created and closed as needed.
For example when you call ExchangeService.FindItems a new HTTP connection to the Exchange server is created and closed within the method call to FindItems.
I realize that this is pretty old, but I had the same question recently, because we've had a problem after connecting to a mailbox, and trying the same method again soon after, we get an HTTP exception. Then, after waiting a minute or so, we can connect...but like the comments on the accepted answer, this is probably a setting on the Exchange server.
To answer the question, technically speaking, since ExchangeService does not implement IDisposable, then there is no need to Dispose a connection, nor could you wrap an instance in a using statement.
private static void ProcessMail()
{
ExchangeService exchange = new ExchangeService();
exchange.Credentials = new WebCredentials(sACCOUNT, sPASSWORD, sDOMAIN);
exchange.AutodiscoverUrl(sEMAIL_ADDRESS);
if (exchange != null)
{
Folder rootFolder = Folder.Bind(exchange, WellKnownFolderName.Inbox);
rootFolder.Load();
foreach (Folder folder in rootFolder.FindFolders(new FolderView(100)))
{
//your code
}
exchange = null;
}
}