exchange api push notification response - exchangewebservices

I am using exchange managed API and using push notification.
I am using below code
Uri uri = new Uri("http://domain.io/MyPage.aspx");
PushSubscription ps = service.SubscribeToPushNotifications(folder, uri, 1, "", EventType.Created, EventType.Modified, EventType.Deleted);
Now i get a hit on domain.io/MyPage.aspx when i change a event from calendar.
But now how i process that response ?
There is limited value in request header.
how could i know that which calendar, which service this request come.

Here is my answer. Using API Call is more simple.
public HttpResponseMessage ExchangeCalendar()
{
string itemId = string.Empty;
string subscriptionId = string.Empty;
string pushResponse = "OK";
string RESPONSE_OK = string.Empty;
HttpContent requestContent = Request.Content;
string eventData = requestContent.ReadAsStringAsync().Result;
XmlDocument doc = new XmlDocument();
doc.LoadXml(eventData);
subscriptionId = GetNodeValue(doc.GetElementsByTagName("t:SubscriptionId"));
itemId = GetNodeValue(doc.GetElementsByTagName("t:ItemId"));
calendarId = GetNodeValue(doc.GetElementsByTagName("t:FolderId"));
RESPONSE_OK = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope\"><soap:Body><SendNotificationResult xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\"><SubscriptionStatus>" + pushResponse + "</SubscriptionStatus></SendNotificationResult></soap:Body></soap:Envelope>";
return new HttpResponseMessage()
{
Content = new StringContent(RESPONSE_OK, Encoding.UTF8, "text/xml")
};
}

In very basic terms, after the SubscribeToPushNotifications call returns the PushSubscription there will be a subscription id that links the folder you subscribed to. Any notifications for that folder will contain the subscription id and the ItemId, as well as the type of notification, New, Changed, Moved, etc. You will need to maintain some kind of mapping of subscription id-to-folder, and then call EWS via GetItem to find the item in question.

Related

Use refresh token in Google's People API Client Library for .NET

I am rewriting an app that used Google Contacts API (RIP) to use People API. I already have a refresh token. Previously, I created an instance of the OAuth2Parameters object, and used it to create an instance of the RequestSettings class to be passed to the ContactsRequest constructor
OAuth2Parameters oparams = new OAuth2Parameters
{
AccessToken = tokenData.access_token,
RefreshToken = tokenData.refresh_token,
ClientId = ClientId,
ClientSecret = ClientSecret,
AccessType = "offline",
ApprovalPrompt = "force",
Scope = _contactScope
};
if (string.IsNullOrWhiteSpace(oparams.AccessToken))
{
oparams.AccessToken = "xyz"; //it doesn't matter what this token is, it just can't be blank, it will get refreshed
OAuthUtil.RefreshAccessToken(oparams);
dataStore._storedResponse.access_token = oparams.AccessToken;
}
var settings = new RequestSettings("My App")
{
OAuth2Parameters = oparams
};
if (paging)
{
settings.PageSize = 50;
settings.AutoPaging = true;
}
return new ContactsRequest(settings);
I cannot figure out how to do the same in the new world of People API. I obviously need to use PeopleServiceService object, but its constructor takes an instance of the Initializer object, and I don't know out how I can initialize it with the refresh token and (possibly) access token.
Here's the official tutorial on how to do authentication with the .NET library for all Google APIs:
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth
Here's a useful snippet from it that will also help with persisting the refresh token to a file and use it in future authentication attempts:
UserCredential credential;
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { BooksService.Scope.Books },
"user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
}
// Create the service.
var service = new BooksService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Books API Sample",
});
var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync();

Why 2 Different JSON Results with String Parameter Search using RestSharp?

If I hard code the band name in my client request with RestSharp I get the results I expect. If I pass in the String I get a different result set. I checked the url it formed and they are the same. Any ideas? I don't use both, I will comment one out and use the other for testing this scenario.
ArtistInfoResponse IMusicRepository.GetArtistResponse(string artistName)
{
var client = new RestClient($"https://api.deezer.com/search?q=artist:{artistName}");
// returns this as url https://localhost:44343/Home/ArtistInformation?artistName=Dave%20Matthews%20Band
var client = new RestClient($"https://api.deezer.com/search?q=artist:\"Dave Matthews Band\"");
// returns this in url https://localhost:44343/Home/ArtistInformation?artistName=Dave%20Matthews%20Band
var request = new RestRequest(Method.GET);
var cancellationTokenSource = new CancellationTokenSource();
IRestResponse response = client.Execute(request);
if (response.IsSuccessful)
{
// Deserialize the string content into JToken object
var content = JsonConvert.DeserializeObject<JToken>(response.Content);
// Deserialize the JToken object into our ArtistInfoResponse Class
return content.ToObject<ArtistInfoResponse>();
}
return null;
}

POST json to external API in .NET Core - Unsupported Media Type

I'm trying to code a middleman API that logs calls and other details from internal users to an external API.
When I try to POST to the external API from my Controller, I get 415 unsupported media type.
I set up my client in the controller constructor like this:
client.BaseAddress = new Uri("https://restapi.***.com/customers/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-AppSecretToken", Auth.APPSECRETTOKEN);
client.DefaultRequestHeaders.Add("X-AgreementGrantToken", Auth.AGREEMENTGRANTTOKEN);
My POST method looks like this:
var json = JsonConvert.SerializeObject(customer, Formatting.Indented);
using (var stringContent = new StringContent(json))
{
stringContent.Headers.ContentType.CharSet = "";
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.ID }, customer);
I've been looking around and found a lot of comments telling me to use Stringcontent, but I also found a couple of responses saying ByteArrayContent - none of them work.
Can anyone help me?
EDIT: When I run the code with breakpoints it seems like some of the properties in the incoming customer object are set even though I didn't set them in my Postman call.
Example; the external API returns a customernumber when I give it the 5 properties that are obligatory. But when I call my internal API from Postman, sending only those 5 obligatory properties, it autopopulates the customernumber with a 0.
Could this be the source of the error? and how do I tell .net core to not autopopulate the customernumber?
EDIT2: I changed my stringContent to include encoding and used a different overload, so the using line now says
using (var stringContent = new StringContent(json, Encoding.UTF8, "application/json"))
And I removed
stringContent.Headers.ContentType.Charset = "";
to reflect the fact that I tried setting the encoding.
The return code changed from 415 to 400 Bad Request when I changed that.
EDIT3:
Tried NOT serializing with Json.Net, and instead used JObjects and Jproperties;
public async Task<ActionResult<Customer>> PostCustomer([FromBody]Customer customer)
{
JObject payload = new JObject(
new JProperty("currency", customer.Currency),
new JProperty("name", customer.Name),
new JProperty("customergroup",
new JObject(new JProperty("customergroupNumber",
customer.CustomerGroup.CustomerGroupNumber)
)),
new JProperty("paymentTerms",
new JObject(new JProperty("paymentTermsNumber",
customer.PaymentTerms.PaymentTermsNumber)
)),
new JProperty("vatZone",
new JObject(new JProperty("vatZoneNumber",
customer.VatZone.VatZoneNumber)
))
);
using (var stringContent = new StringContent(payload.ToString(), Encoding.UTF8, "application/json"))
{
HttpResponseMessage response = await client.PostAsync(client.BaseAddress, stringContent);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode);
}
}
return CreatedAtAction("GetCustomer", new { id = customer.CustomerNumber }, customer);
}
Still 400 Bad Request
This is a case of capitalizing - simple really.
My POST request JSON had an object named customergroup - changed it to customerGroup, and it worked.

How to send OK or Unsubscribe response to EWS PUSH notification

I am using exchange api Push notification in C#.
I receive exchange api push notification on .aspx page(C#) in Request.InputStream.
Now I Need to send OK response. But my problem is that where i Have to send this response. I mean which URL and how.
Please help me with C# code.
Below is my code :
I have see some example on google so i try to send SOAP message :
string oRequest = "";
oRequest = "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
oRequest += "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\" xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">";
oRequest += "<soap:Body><m:SendNotificationResult><m:SubscriptionStatus>Ok</m:SubscriptionStatus></m:SendNotificationResult></soap:Body>";
oRequest += "</soap:Envelope>";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("This is the URL which i provide to exchange when i create subsricption. Is this wrong, What will be the URL");
req.Headers.Add("SOAPAction", "http://schemas.microsoft.com/exchange/services/2006/messages/SendNotification")
req.ContentType = "text/xml; charset=\"utf-8\"";
req.Accept = "text/xml";
req.Method = "POST";
//Passes the SoapRequest String to the WebService
using (Stream stm = req.GetRequestStream())
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(oRequest);
}
}
//Gets the response
WebResponse response = req.GetResponse();
//Writes the Response
Stream responseStream = response.GetResponseStream();
StreamReader sr = new StreamReader(responseStream);
string s = sr.ReadToEnd();
Push notifications are automatically sent to the web service listener (the callback URL specified in the subscription request).
when push notifications send events to your web service listener. your can send your response (OK or Unsubscribe).
You do not need to call the url of exchange.
You can refer:
https://msdn.microsoft.com/en-us/library/office/dn458791(v=exchg.150).aspx

Salesforce JSON POST works for standard objects by not custom object

I am using the Salesforce REST API. I have created a new custom object within SFDC and want to POST data to it. I can happily POST JSON documents to the standard SFDC objects such as Account or Contact. However, when I try posting to my custom object I receive a timeout from SFDC.
Here is the method I am using to perform all POSTS (whether standard or custom)
public static BsonDocument PostJSONToSFDC(string uri, BsonDocument postDoc, string method, HPSUtilities.Transformation.Transformation transformation)
{
string accessToken = transformation.sfdcAccess.accessToken;
string instanceUri = transformation.sfdcAccess.instanceUri;
string uri2 = instanceUri + uri;
System.Net.WebRequest req = System.Net.WebRequest.Create(uri2);
req.ContentType = "application/json";
req.Method = method;// "POST" or "PATCH"; // a PATCH alternative uses POST with url parm="?_HttpMethod=PATCH"
req.Headers.Add("Authorization: Bearer " + accessToken);
string postDocAsString = postDoc.ToJson();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postDocAsString);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length); //Push it out there
os.Close();
System.Net.WebResponse resp = req.GetResponse();
if (resp == null) return null;
System.IO.StreamReader sr =
new System.IO.StreamReader(resp.GetResponseStream());
string rs = sr.ReadToEnd().Trim();
MongoDB.Bson.BsonDocument doc2;
if (rs.Equals("") && method.Equals("PATCH", StringComparison.CurrentCultureIgnoreCase))
{
// For successful PATCHs (updates), SFDC mysteriously returns a completely empty response.
// In this case let's create something more meaningful!
doc2 = new BsonDocument();
doc2.Add("success", "true");
}
else
{
doc2 = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<MongoDB.Bson.BsonDocument>(rs);
}
return doc2;
}
Given that this code works when POSTing or PATCHing to SFDC I believe that I must be hitting some sort of SFDC restriction for custom objects. Is it necessary to mark SFDC custom objects as API-enabled? Is anyone aware of any other issues that might be causing my timeout?