I'm using EWS API for consuming outlook 365 mail service.
When I'm performing any mail operation it's running slow.
I have written the code mentioned below:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
service.Credentials = new WebCredentials("usernm", "pwd");
service.EnableScpLookup = false;
service.AutodiscoverUrl("user",RedirectionUrlValidationCallback);
That last line takes 16 seconds before the connection is successful.
Is there any way to make the performance faster?
Hard to say...not saying this is the answer
but try this and let me know.
I see a difference in that i dont pass RedirectionUrlValidationCallback in the autoDiscoverUrl and I don't set EnableScpLookup flag, dont know what that is for. let me know
public ExchangeService GetService( string autoDiscoverEmailAddress, string authEmailAddress,string authEmailPassword, string domain = null, ExchangeVersion verion = ExchangeVersion.Exchange2010_SP2 )
{
try
{
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
ExchangeService svc = new ExchangeService(verion);
//svc.UseDefaultCredentials = true;
if (!string.IsNullOrWhiteSpace(domain))
{
svc.Credentials = new WebCredentials(authEmailAddress, authEmailPassword, domain);
}
else
{
svc.Credentials = new WebCredentials(authEmailAddress, authEmailPassword);
}
svc.AutodiscoverUrl(autoDiscoverEmailAddress);
return svc;
}
catch (Exception)
{
throw;
}
}
Related
I have developed web API with this method and I test it with Advanced Rest Client in my machine and everything is alright, but after deploy to server the result is omitted by the server and not recognize as valid JSON text and not parse correctly.
[Route("[action]")]
[HttpGet]
public async Task<JsonResult> GetAllCityEvent(string apiKey)
{
List<CityMapMarker> availableMapMarkers = new List<CityMapMarker>();
PersianUtilCore.Api.MethodResult result = new PersianUtilCore.Api.MethodResult();
List<PersianUtilCore.Api.MethodError> errors = new List<PersianUtilCore.Api.MethodError>();
ApiBO apiBO = new ApiBO(AggregateService);
bool isValidKey = apiBO.IsValidKey(apiKey);
if (!isValidKey)
{
result.IsSuccess = false;
errors.Add(new PersianUtilCore.Api.MethodError(300, "your key is not valid!"));
}
else
{
JunctionBO junctionBO = new JunctionBO(AggregateService);
StreetBO streetBO = new StreetBO(AggregateService);
HighwayBO highwayBO = new HighwayBO(AggregateService);
SightBO sightBO = new SightBO(AggregateService);
TrafficLightBO trafficLightBO = new TrafficLightBO(AggregateService);
CameraBO cameraBO = new CameraBO(AggregateService);
TransportationStationBO bussStationBO = new TransportationStationBO(AggregateService);
TrafficBO trafficBO = new TrafficBO(AggregateService);
CityEventBO cityEventBO = new CityEventBO(AggregateService);
//availableMapMarkers.AddRange(junctionBO.CityMapMarkers());
//availableMapMarkers.AddRange(streetBO.CityMapMarkers());
//availableMapMarkers.AddRange(highwayBO.CityMapMarkers());
//availableMapMarkers.AddRange(sightBO.CityMapMarkers());
//availableMapMarkers.AddRange(trafficLightBO.CityMapMarkers());
//availableMapMarkers.AddRange(trafficBO.CityMapMarkers());
//availableMapMarkers.AddRange(cameraBO.CityMapMarkers());
availableMapMarkers.AddRange(bussStationBO.CityMapMarkers(TransportationType.Bus));
availableMapMarkers.AddRange(bussStationBO.CityMapMarkers(TransportationType.Train));
availableMapMarkers.AddRange(bussStationBO.CityMapMarkers(TransportationType.BRT));
availableMapMarkers.AddRange(cityEventBO.CityMapMarkers());
result.Result = availableMapMarkers;
result.IsSuccess = true;
}
result.Errors = errors;
result.Result = availableMapMarkers;
result.IsSuccess = errors.Count <= 0;
var logHistoryResult = apiBO.LogHistory(apiKey, nameof(this.GetAllCityEvent));
return Json(result);
}
I couldn't find any way to change JsonResult max length like with I did in Asp.net MVC4 or Asp.net Webforms
How can I increase JsonResult maxlength in MVC Core?
Why there is different in IIS publish or local machine when I try to get result from my web API?
I have a web API returning 117k JSON objects.
Edit: The API is calling MySQL to fetch 117k rows of data, putting them into a IEnumerable and sending them through JSON
All I see is
[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},... the entire page...
I wanted to ask how someone what is happening and how you would handle a large JSON transfer. Prefer to get it all in one go to avoid querying back and forth (delay time).
The function call is this:
public IEnumerable<Score> Get(int id)
{
string mConnectionString = System.Configuration.ConfigurationManager.AppSettings["mysqlConnectionString"];
MySqlConnection mConn;
MySqlDataReader mReader;
List<Score> returnedRows = new List<Score>();
if (String.IsNullOrEmpty(mConnectionString))
{
return returnedRows;
}
try
{
// prepare the dump query
MySqlCommand dumpCmd;
string query = "SELECT * FROM score where id = "+id+";";
using (mConn = new MySqlConnection(mConnectionString))
{
using (dumpCmd = new MySqlCommand())
{
dumpCmd.Connection = mConn;
dumpCmd.CommandText = query;
mConn.Open();
mReader = dumpCmd.ExecuteReader(); /
if (mReader.HasRows)
{
while (mReader.Read())
{
string[] rowCols = new string[mReader.FieldCount]; // there are 20+ columns, at least the primary keys are not null
for (int i = 0; i < rowCols.Length; ++i)
{
rowCols[i] = mReader.GetString(i);
}
returnedRows.Add(new Score(rowCols));
}
mConn.Close();
return returnedRows;
}
else
{
// should return a 404 cause nothing found
mConn.Close();
}
}
}
}
catch (Exception e)
{
return returnedRows;
}
return returnedRows;
}
Either mReader.GetString(i) is returning null or you have no data in the columns.
My WP8 app is fetching old data instead of updated data when I run the query:
private async Task fetchParseData()
{
try
{
var query = ParseObject.GetQuery("Favorite")
.WhereEqualTo("user", ParseUser.CurrentUser.Username);
IEnumerable<ParseObject> results = await query.FindAsync();
this.favorites.Clear();
foreach (ParseObject result in results)
{
string venue = result.Get<string>("venue");
string address = result.Get<string>("address");
string likes = result.Get<string>("likes");
string price = result.Get<string>("price");
string contact = result.Get<string>("contact");
this.favorites.Add(new ItemViewModel { LineOne = venue, LineTwo = address, LineThree = likes, Rating = "", Hours = "", Contact = contact, Price = price, Latitude = "", Longitude = "" });
}
if (favorites.Count == 0)
{
// emailPanorama.DefaultItem = emailPanorama.Items[1];
MessageBox.Show("You do not have any saved cafes. Long press a cafe in main menu to save it.");
}
}
catch (Exception exc)
{
MessageBox.Show("Data could not be fetched!", "Error", MessageBoxButton.OK);
}
}
Can you please help me find where the problem is in this query. I debugged and found error in only this part. SO, my new data is not being fetched by the query.findasync() method.
Windows Phones Web Cache is quite aggressive.
If the servier you are querying from does not explicitly set a cache-duration in the http headers, windows phone will cache all requests (don't know the duration though, but pretty long).
You can:
Set the "Cache-Control: no-cache" Header on your server.
Add a random number (or timestamp) to each request so the uri differs.
Try add the "if-modified-since" header to your requests.
See this question for details.
If I derive all of my exceptions from WebFaultException, and throw them directly from my services, the StatusCode set in the WebFaultException gets passed to the client. I'd rather not have to do that, since I'd rather throw generic exceptions like NotImplementedException, from my code.
I've set up an IErrorHandler, with the expectation that I'd be able to catch exceptions like NotImplementedException, and then just do the conversion to a WebFaultException there.
My code looks like this:
public class HTTPBindingErrorHandler: IErrorHandler
{
public void ProvideFault(Exception exception, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
if (exception is NotImplementedException)
{
WebFaultException wfe = new WebFaultException(HttpStatusCode.NotImplemented);
MessageFault mf = wfe.CreateMessageFault();
fault = Message.CreateMessage(version, mf, wfe.Action);
}
}
public bool HandleError(Exception exception)
{
return false;
}
}
When stepping through, I see that I'm getting to the code in ProvideFault, but the Status returned to the client is 400, not 501. Additionally, the body is:
<Fault
xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
<Code>
<Value>Receiver</Value>
<Subcode>
<Value
xmlns:a="http://schemas.microsoft.com/2009/WebFault">a:NotImplemented
</Value>
</Subcode>
</Code>
<Reason>
<Text xml:lang="en-US">Not Implemented</Text>
</Reason>
</Fault>
Why isn't the correct status code being returned?
Why isn't the body
in json?
Addition:
I've tried the recommendation of setting AutomaticFormatSelectionEnabled = false to the webhttpbehavior, but it still does not work. I'm self hosting, but I don't think that should make the difference. Here is the code I use to set up the service:
Uri newUri = new Uri(info.baseURI, info.Path);
WebServiceHost host = new WebServiceHost(info.Type, newUri);
WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.TransportCredentialOnly);
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.InheritedFromHost;
ServiceEndpoint ep = host.AddServiceEndpoint(info.Interface, binding, newUri);
ep.Behaviors.Add(new WebHttpBehavior() {
DefaultOutgoingResponseFormat = WebMessageFormat.Json,
DefaultBodyStyle = WebMessageBodyStyle.Wrapped,
AutomaticFormatSelectionEnabled = false } );
ep.Behaviors.Add(new WebHttpCors.CorsSupportBehavior());
ep.Behaviors.Add(new HTTPBindingErrorBehavior());
I tried posting this on the Exchange Development forum and didnt get any replies, so I will try here. Link to forum
I have a windows services that fires every fifteen minutes to see if there is any subscriptions that need to be created or updated. I am using the Managed API v1.1 against Exchange 2007 SP1. I have a table that stores all the users that want there mailbox monitored. So that when a notifcation comes in to the "Listening Service" I am able to look up the user and access the message to log it into the application we are building. In the table I have the following columns that store the subscription information:
SubscriptionId - VARCHAR(MAX)
Watermark - VARCHAR(MAX)
LastStatusUpdate - DATETIME
My services calls a function that queries the data needed (based on which function it is doing). If the user doesn't have a subscription already the service will go and create one. I am using impersonation to access the mailboxes. Here is my "ActiveSubscription" method that is fired when a user needs the subscription either created or updated.
private void ActivateSubscription(User user)
{
if (user.ADGUID.HasValue)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, Settings.ActiveDirectoryServerName, Settings.ActiveDirectoryRootContainer);
using (UserPrincipal up = UserPrincipal.FindByIdentity(ctx, IdentityType.Guid, user.ADGUID.Value.ToString()))
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SID, up.Sid.Value);
}
}
else
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress);
}
PushSubscription pushSubscription = ewService.SubscribeToPushNotifications(
new FolderId[] { WellKnownFolderName.Inbox, WellKnownFolderName.SentItems },
Settings.ListenerService, 30, user.Watermark,
EventType.NewMail, EventType.Created);
user.Watermark = pushSubscription.Watermark;
user.SubscriptionID = pushSubscription.Id;
user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime();
_users.Update(user);
}
We have also ran the following cmdlet to give the user we are accessing the EWS with the ability to impersonate on the Exchange Server.
Get-ExchangeServer | where {$_.IsClientAccessServer -eq $TRUE} | ForEach-Object {Add-ADPermission -Identity $_.distinguishedname -User (Get-User -Identity mailmonitor | select-object).identity -extendedRight ms-Exch-EPI-Impersonation}
The "ActivateSubscription" code above works as expected. Or so I thought. When I was testing it I had it monitoring my mailbox and it worked great. The only problem I had to work around was that the subscription was firing twice when the item was a new mail in the inbox, I got a notification for the NewMail event and Created event. I implemented a work around that checks to make sure the message hasn't already been logged on my Listening service. It all worked great.
Today, we started testing two mailboxes being monitor at the same time. The two mailboxes were mine and another developers mailbox. We found the strangest behavior. My subscription worked as expected. But his didn't, the incoming part of his subscription work properly but any email he sent out the listening service never was sent a notification. Looking at the mailbox properties on Exchange I don't see any difference between his mailbox and mine. We even compared options/settings in Outlook. I can see no reasons why it works on my mailbox and not on his.
Is there something that I am missing when creating the subscription. I didn't think there was since my subscription works as expected.
My listening service code works perfectly well. I have placed the code below incase someone wants to see it to make sure it is not the issue.
Thanks in advance, Terry
Listening Service Code:
/// <summary>
/// Summary description for PushNotificationClient
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class PushNotificationClient : System.Web.Services.WebService, INotificationServiceBinding
{
ExchangeService ewService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
public PushNotificationClient()
{
//todo: init the service.
SetupExchangeWebService();
}
private void SetupExchangeWebService()
{
ewService.Credentials = Settings.ServiceCreds;
try
{
ewService.AutodiscoverUrl(Settings.AutoDiscoverThisEmailAddress);
}
catch (AutodiscoverRemoteException e)
{
//log auto discovery failed
ewService.Url = Settings.ExchangeService;
}
}
public SendNotificationResultType SendNotification(SendNotificationResponseType SendNotification1)
{
using (var _users = new ExchangeUser(Settings.SqlConnectionString))
{
var result = new SendNotificationResultType();
var responseMessages = SendNotification1.ResponseMessages.Items;
foreach (var responseMessage in responseMessages)
{
if (responseMessage.ResponseCode != ResponseCodeType.NoError)
{
//log error and unsubscribe.
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
var sendNoficationResponse = responseMessage as SendNotificationResponseMessageType;
if (sendNoficationResponse == null)
{
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
var notificationType = sendNoficationResponse.Notification;
var subscriptionId = notificationType.SubscriptionId;
var previousWatermark = notificationType.PreviousWatermark;
User user = _users.GetById(subscriptionId);
if (user != null)
{
if (user.MonitorEmailYN == true)
{
BaseNotificationEventType[] baseNotifications = notificationType.Items;
for (int i = 0; i < notificationType.Items.Length; i++)
{
if (baseNotifications[i] is BaseObjectChangedEventType)
{
var bocet = baseNotifications[i] as BaseObjectChangedEventType;
AccessCreateDeleteNewMailEvent(bocet, ref user);
}
}
_PreviousItemId = null;
}
else
{
user.SubscriptionID = String.Empty;
user.SubscriptionStatusDateTime = null;
user.Watermark = String.Empty;
_users.Update(user);
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime();
_users.Update(user);
}
else
{
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
}
result.SubscriptionStatus = SubscriptionStatusType.OK;
return result;
}
}
private string _PreviousItemId;
private void AccessCreateDeleteNewMailEvent(BaseObjectChangedEventType bocet, ref User user)
{
var watermark = bocet.Watermark;
var timestamp = bocet.TimeStamp.ToLocalTime();
var parentFolderId = bocet.ParentFolderId;
if (bocet.Item is ItemIdType)
{
var itemId = bocet.Item as ItemIdType;
if (itemId != null)
{
if (string.IsNullOrEmpty(_PreviousItemId) || (!string.IsNullOrEmpty(_PreviousItemId) && _PreviousItemId != itemId.Id))
{
ProcessItem(itemId, ref user);
_PreviousItemId = itemId.Id;
}
}
}
user.SubscriptionStatusDateTime = timestamp;
user.Watermark = watermark;
using (var _users = new ExchangeUser(Settings.SqlConnectionString))
{
_users.Update(user);
}
}
private void ProcessItem(ItemIdType itemId, ref User user)
{
try
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress);
EmailMessage email = EmailMessage.Bind(ewService, itemId.Id);
using (var _entity = new SalesAssistantEntityDataContext(Settings.SqlConnectionString))
{
var direction = EmailDirection.Incoming;
if (email.From.Address == user.EmailAddress)
{
direction = EmailDirection.Outgoing;
}
int? bodyType = (int)email.Body.BodyType;
var _HtmlToRtf = new HtmlToRtf();
var message = _HtmlToRtf.ConvertHtmlToText(email.Body.Text);
bool? IsIncoming = Convert.ToBoolean((int)direction);
if (IsIncoming.HasValue && IsIncoming.Value == false)
{
foreach (var emailTo in email.ToRecipients)
{
_entity.InsertMailMessage(email.From.Address, emailTo.Address, email.Subject, message, bodyType, IsIncoming);
}
}
else
{
if (email.ReceivedBy != null)
{
_entity.InsertMailMessage(email.From.Address, email.ReceivedBy.Address, email.Subject, message, bodyType, IsIncoming);
}
else
{
var emailToFind = user.EmailAddress;
if (email.ToRecipients.Any(x => x.Address == emailToFind))
{
_entity.InsertMailMessage(email.From.Address, emailToFind, email.Subject, message, bodyType, IsIncoming);
}
}
}
}
}
catch(Exception e)
{
//Log exception
using (var errorHandler = new ErrorHandler(Settings.SqlConnectionString))
{
errorHandler.LogException(e, user.UserID, user.SubscriptionID, user.Watermark, user.SubscriptionStatusDateTime);
}
throw e;
}
}
}
I have two answers for you.
At first you will have to create one instance of ExchangeService per user. Like I understand your Code you just create one instance and switch the impersonation, which is not supported. I developed a windowsservice which is pretty similar to yours. Mine is synchronising the mails between our CRM and Exchange. So at startup I create an instance per user and Cache it as long as the application runs.
Now about cache-mode. The diffrence between using cache-mode and not is just a timing gab. In cache-mode Outlook synchronizes from time to time. And non cached it's in time. When you use the cache-mode and want the Events immediatly on your Exchange-Server you can press the "send and receive"-button in Outlook to force the sync.
Hope that helps you...