FCM with Parse Server Push Notifications mismatchsenderid and client app error - c#

I used to try this with GCM but I couldn't get it to work with Parse Server .. So I took a stackoverflow users advice and gave it a try with FCM .
My device gets the registration id from FCM like this :
04-15 17:01:29.773 I/parse.GcmRegistrar(30144): GCM registration successful. Registration Id: APA91bFoNUPYdsjN6O_CkPje-O0hXjNz9kvURZMex72xClyBr_5o6D0vYtI-F0iyAGgSYjpIEaJt2QQ2CXk2qpI11gPFUSUdzH-NxQRXSK3hPkuaiC_lciVV3E0fp6A_VZUoYJ8VxOIh
I tried to send a notification from the firebase console with this ID and its working my event gets fired and its all good .
The problem starts when i want to use ParseCloud function to send notifications to my users. While I was searching the device output log for errors i found this one :
04-15 17:01:25.490 E/parse.GcmRegistrar(30144): Found com.parse.push.gcm_sender_id <meta-data> element with value "id:767075137222", but the value is missing the expected "id:" prefix
This one is weird cause my manifest includes the gcm_sender_id plus it includes the prefix id: Here is my manifest
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.companyname.appname.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.companyname.appname.permission.C2D_MESSAGE" />
<application android:label="Fuse.Android" android:icon="#mipmap/ic_launcher">
<service android:name="parse.ParsePushService" />
<receiver android:name="parse.ParsePushBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.companyname.appname" />
</intent-filter>
</receiver>
<meta-data android:name="com.parse.push.gcm_sender_id"
android:value="id:767075137222"/>
</application>
I searched online and people were saying that this problem comes when you're not using the right API KEY & Sender Id .. I'm using these :
Next my index for Parse Server looks like this :
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var pushConfig = {};
if (process.env.GCM_SENDER_ID && process.env.GCM_API_KEY) {
pushConfig['android'] = {
senderId: process.env.GCM_SENDER_ID || '',
apiKey: process.env.GCM_API_KEY || ''};
}
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
push: pushConfig,
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
}
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
I've defined the GCM_SENDER_ID and GCM_API_KEY to the config vars of the Heroku hosting Parse .
After i call the ParseCloud function from the client app i get this in the heroku logs :
Apr 15 08:03:02 fuseparse app/web.1: } method=POST, url=/parse/push, host=fuseparse.herokuapp.com, connection=close, user-agent=node-XMLHttpRequest, Parse/js1.11.1 (NodeJS 9.11.1), accept=*/*, content-type=text/plain, x-request-id=ea046fd0-5fb7-46b7-9ceb-e6a0fd2ebad1, x-forwarded-for=54.81.77.161, x-forwarded-proto=https, x-forwarded-port=443, via=1.1 vegur, connect-time=0, x-request-start=1523804582292, total-route-time=0, content-length=270, installationId=e2dc9f85-3c2f-464e-beca-c8b9d2cba528, alert=The Giants scored!
Apr 15 08:03:02 fuseparse app/web.1: verbose: RESPONSE from [POST] /parse/push: {
Apr 15 08:03:02 fuseparse app/web.1: "headers": {
Apr 15 08:03:02 fuseparse app/web.1: "X-Parse-Push-Status-Id": "upnMh1652U"
Apr 15 08:03:02 fuseparse app/web.1: },
Apr 15 08:03:02 fuseparse app/web.1: "response": {
Apr 15 08:03:02 fuseparse app/web.1: "result": true
Apr 15 08:03:02 fuseparse app/web.1: }
Apr 15 08:03:02 fuseparse app/web.1: } X-Parse-Push-Status-Id=upnMh1652U, result=true
Apr 15 08:03:02 fuseparse app/web.1: #### PUSH OK
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: sending push to installations with 1 batches
Apr 15 08:03:02 fuseparse app/web.1: verbose: Sending push to 1
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM sending to 1 device
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM GCM Response: {
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "multicast_id": 5516369214301735000,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "success": 0,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "failure": 1,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "canonical_ids": 0,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "results": [
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM {
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "error": "MismatchSenderId"
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM }
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM ]
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM }
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: sent push! 0 success, 1 failures
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: needs cleanup devicesToRemove=[]
I've been at it for days .. Can somebody tell me if what im trying to do is possible and if it is possible where i might be doing this wrong ???

if you are using fcm notification you need to add this in your manifest !
<!-- Firebase Notifications -->
<service android:name=".HERE_YOUR_CLASS_WHICH_EXTENDS_FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".HERE_YOUR_CLASS_WHICH_EXTENDS_FirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<!-- ./Firebase Notifications -->

Whoever has a problem with this error :
04-15 17:01:25.490 E/parse.GcmRegistrar(30144): Found com.parse.push.gcm_sender_id <meta-data> element with value "id:767075137222", but the value is missing the expected "id:" prefix
but has defined the gcm_sender_id in the androidmanifest most likely has a faulty sdk or parse.dll installed . What i did is I downloaded the open source SDK which is available in the parseplatform github and modified the GcmRegistrar.cs class to not return null for the sender_id :
This took me a long time but for anyone who has the same problem pls download the latest .dll or if the problem still persists it means that the dll was not updated and you have to manually do this . In my case i was using the .NET Sdk and it wasn't updated .
Download the open source sdk and replace Internal/Push/GcmRegistrar.cs with this
using System;
using Android.App;
using Android.Content;
using Android.OS;
using System.Threading.Tasks;
namespace Parse {
internal class GcmRegistrar {
private const string LogTag = "parse.GcmRegistrar";
private const string ExtraRegistrationId = "registration_id";
private const string ExtraSenderId = "com.parse.push.gcm_sender_id";
private const string ParseGcmSenderId = "1076345567071";
public const string IntentRegisterAction = "com.google.android.c2dm.intent.REGISTER";
private readonly Object mutex = new Object();
private Request request;
private Context context;
public static GcmRegistrar GetInstance() {
return Singleton.Instance;
}
private static class Singleton {
public static readonly GcmRegistrar Instance = new GcmRegistrar(Application.Context);
}
private GcmRegistrar(Context context) {
this.context = context;
}
private string getActualSenderIdFromExtra(Object senderIdExtra) {
if (senderIdExtra == null ) {
return null;
}
string senderId = senderIdExtra.ToString();
if (!senderId.StartsWith("id:")) {
return null;
}
return senderId.Substring(3);
}
public void Register() {
ParseInstallation installation = ParseInstallation.CurrentInstallation;
lock (mutex) {
if (installation.DeviceToken == null && request == null) {
var metadata = ManifestInfo.GetApplicationMetaData();
object senderIdExtra = null;
if (metadata != null) {
senderIdExtra = metadata.Get(ExtraSenderId);
}
string senderIds = ParseGcmSenderId;
if (senderIdExtra != null) {
string senderId = getActualSenderIdFromExtra(senderIdExtra);
if (senderId != null) {
senderIds += "," + senderId;
} else {
Android.Util.Log.Error("parse.GcmRegistrar", "Found " + ExtraSenderId + " <meta-data> element with value \""
+ senderIdExtra.ToString() + "\", but the value is missing the expected \"id:\" prefix");
}
}
request = Request.CreateAndSend(this.context, senderIds);
}
}
}
/// <summary>
/// Handles GCM registration intent from <see cref="ParsePushBroadcastReceiver"/> and saves the GCM registration
/// id as <see cref="ParseInstallation.CurrentInstallation"/> device token.
/// </summary>
/// <remarks>
/// Should be called by a broadcast receiver or service to handle GCM registration response
/// intent (com.google.android.c2dm.intent.REGISTRATION).
/// </remarks>
/// <param name="intent"></param>
public Task HandleRegistrationIntentAsync(Intent intent) {
if (intent.Action == ParsePushBroadcastReceiver.ActionGcmRegisterResponse) {
string registrationId = intent.GetStringExtra(ExtraRegistrationId);
if (registrationId != null && registrationId.Length > 0) {
Android.Util.Log.Info(LogTag, "GCM registration successful. Registration Id: " + registrationId);
ParseInstallation installation = ParseInstallation.CurrentInstallation;
// Set `pushType` via internal `Set` method since we want to skip mutability check.
installation.Set("pushType", "gcm");
installation.DeviceToken = registrationId;
return installation.SaveAsync();
}
}
return Task.FromResult(0);
}
/// <summary>
/// Encapsulates the GCM registration request-response, potentially using <c>AlarmManager</c> to
/// schedule retries if the GCM service is not available.
/// </summary>
private class Request {
private Context context;
private string senderId;
private PendingIntent appIntent;
public static Request CreateAndSend(Context context, string senderId) {
Request request = new Request(context, senderId);
request.Send();
return request;
}
private Request(Context context, string senderId) {
this.context = context;
this.senderId = senderId;
appIntent = PendingIntent.GetBroadcast(context, 0, new Intent(), 0);
}
private void Send() {
Intent intent = new Intent(IntentRegisterAction);
intent.SetPackage("com.google.android.gsf");
intent.PutExtra("sender", senderId);
intent.PutExtra("app", appIntent);
ComponentName name = null;
try {
name = context.StartService(intent);
} catch (Exception) {
// Do nothing.
}
}
}
}
}

Related

How to reproduce a browser handshake in c# to a websocket without receiving a 403?

I'm building a c# application that connects to a websocket using WebSocket-sharp and I keep receiving a 403 - Forbidden from the server.
I have tried using fiddler to see how the browser handle it differently and I have copied all the local cookies the website is using.
The request:
GET /api/trade/live/Metamorph/lg8jphV HTTP/1.1
User-Agent: websocket-sharp/1.0
Host: www.pathofexile.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: pnjDDw0njbxi4PmLR+A6OA==
Sec-WebSocket-Version: 13
Cookie: POESESSID=<redacted>
The response:
HTTP/1.1 403 Forbidden
Date: Sun, 02 Feb 2020 20:32:32 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d31e2345f42cc565e3bbc5e9a2d0ede691580675552; expires=Tue, 03-Mar-20 20:32:32 GMT; path=/; domain=.pathofexile.com; HttpOnly; SameSite=Lax
X-Rate-Limit-Policy: trade-websocket-request-limit
X-Rate-Limit-Rules: Ip
X-Rate-Limit-Ip: 45:60:60,90:120:3600
X-Rate-Limit-Ip-State: 1:60:0,1:120:0
CF-Cache-Status: DYNAMIC
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 55eeef5a1ec4919e-EWR
Any ideas on what would be the next step in troubleshooting the issue would be greatly appreciated!
I've looked at that particular API, and you first have to create a 'search'. That is what your lg8jphV is - the endpoint has to actually exist before you can open it. In my test, for example, my websocket URL is wss://www.pathofexile.com/api/trade/live/Metamorph/Ab3LSL
First post your search to https://www.pathofexile.com/api/trade/search/Metamorph. Your body should look something like this (except with your specific search terms):
{
"query": {
"status": {
"option": "online"
},
"stats": [
{
"type": "and",
"filters": []
}
],
"filters": {
"type_filters": {
"disabled": false,
"filters": {
"category": {
"option": "weapon.bow"
}
}
},
"misc_filters": {
"disabled": false,
"filters": {
"shaper_item": {
"option": "true"
}
}
}
}
},
"sort": {
"price": "asc"
}
}
This creates your actual search object, and you get a response body back like this:
{
"result": [
"48c83eb427f369f6ddde8689d7458f6bf5a8380eed114b72b5a7a298651c4d65",
"6314ac7c88b143b80c777d23cdc12bb9d86e8bb82d8073f659132bf492fa69fe",
"1c39870f03505acaecd78dc0cc2a498a3a1037cd88b0035e3601e35140b59450",
"3dc8cf428d842a8be12953c6d2db117e5db4456cb6d3b75f5280ca8fb687c587",
"9470cc63efbe4ca192103200ad78734784a218c68b9d9ead0be456a98260394f",
"798ba0699085a63359c459cc89cafbbe28653fe893dfb6a9ba71162fd4d7aa51",
"dab3edc9c28723decc76ba56eb988c7f245ce15041640dca461124918dafbc90",
"06da5889c8cbf295ab13e103dfa9e291b3e0caf0256b398ccaec9ddfdb1e56c4",
"... continues ..."
],
"id": "Ab3LSL",
"total": 100000,
"inexact": true
}
You now have a search endpoint via the ID.
Finally, when making the request, you have to set the Origin header or you'll get a 403 Forbidden (you'll have to change the nuget package you're using to https://www.nuget.org/packages/websocket-sharp-customheaders if you want to keep using websocket-sharp). Don't forget your cookie or you'll get 401 Unauthorized
using (ClientWebSocket ws = new ClientWebSocket())
{
Uri serverUri = new Uri($"wss://www.pathofexile.com/api/trade/live/Metamorph/D4bWwf5");
//setting headers the way I did below only works because I used reflection to change the IsRequestRestricted bool to false
ws.Options.SetRequestHeader("Cookie", "__cfduid=d4a76bfa2583a39474272974006edad461580748134; _ga=GA1.2.477754083.1580748162; _gid=GA1.2.2011499591.1580748162; stored_data=1; _sm_au_c=krZJcAOlyMvVNsrvCJ4mJyGIu8S0KVB4Lr7aqcW0VB9UgAAAAa68dX6r0DT/Ta5U0B4NfCgZ2Jm/2q8R651XMxiBtJsM=; cf_clearance=e6964bd6eaed12c405c1b9b8a2b2f08d506b4926-1580761181-0-150; POESESSID=a2c44ee2111904215ccef8c69b2e72b5");
ws.Options.SetRequestHeader("Origin", "https://www.pathofexile.com");
ws.ConnectAsync(serverUri, CancellationToken.None).Wait();
Task.Run(async () =>
{
ArraySegment<byte> inbound = new ArraySegment<byte>(new byte[1024]);
while (ws.State == System.Net.WebSockets.WebSocketState.Open)
{
var wsRes = await ws.ReceiveAsync(inbound, CancellationToken.None);
if (wsRes?.Count > 0)
Console.WriteLine(Encoding.UTF8.GetString(inbound.Array, 0, wsRes.Count));
}
});
Console.WriteLine("WEB SOCKET OPEN; HIT ENTER TO EXIT");
Console.ReadLine();
}
You can run the snippet above, just swap out the cookies for your own cookies. This is also just a rough proof of concept using the built in websocket client.
Screenshot of output:

Web Pushnotification PUSH API and service worker C# - Not seeing notifcation

have followed the steps mentioned in the Push code lab Push Notifications site to integrated Push notification in my dot net ``site
1.register Service worker and also was able to see the Subscription on the page.
Subscription:
Step: have down Loaded the C# Library to send the Push Notifications and have added Test Program to test this C#code. i am able to run the code and no Error were shown but i am not seeing any Push Notification in the Chrome Browser( Kept the same Browser tab opened where i have my Site Running / Also closed the browser and Relaunched to see any Notification).In Either case i am not seeing any Notifications
I am not seeing any Error from the Code an
below is the Response from Web pushClient.
{StatusCode: 201, ReasonPhrase: 'Created', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Alt-Svc: quic=":443"; ma=2592000; v="39,38,37,36,35" Cache-Control: max-age=0, private Date: Wed, 05 Jul 2017 15:59:43 GMT Location: https://fcm.googleapis.com/fcm/0:1499270383802342%e609af1cf9fd7ecd Server: GSE Content-Length: 0 Content-Type: text/plain Expires: Wed, 05 Jul 2017 15:59:43 GMT }}
var pushEndpoint = #"https://fcm.googleapis.com/fcm/send/dKUDjOvvyjg:APA91bF3jr2gsX--KjonylSL_25TfCGG5mVsFZoYgnESYLep2rlWOI6KK1T9Dghr9E8o1e7a0wtOCH2LqmcCV0pjW7ZuDW7wPptJnnXy3XBu4Eo_CX0fLYGqsqy8voU9pFg6eZyaDFab";
var p256dh = #"BMEI2Zz1LPeFBeBtEZlTV_St0PHb6v_OlldbUoE6wrnnx8ychyz4o7tMt_S_Z0bKQj3vOAS0lMuZRRrgO7-LEGo=";
var auth = #"hwrfOP0UUevO5UdB6WRIQw==";
var subject = #"mailto:megan#gmail.com";
var publicKey = #"BK4ITwwSPZpxelX-oaycWnPuRSnRetbu3QBY4hSm5f1Up24PTrktIrJxRXR9bUIqrGx2YFcDCv48sDwFW50jdmI";
var privateKey = #"PEW_j759M2Q218O9le3GS8OnejmwlWYI1-LtNAP31bg";
var subscription = new PushSubscription(pushEndpoint, p256dh, auth);
var vapidDetails = new VapidDetails(subject, publicKey, privateKey);
//var gcmAPIKey = #"[your key here]";
var webPushClient = new WebPushClient();
try
{
webPushClient.SendNotification(subscription, "payload", vapidDetails);
//webPushClient.SendNotification(subscription, "payload", gcmAPIKey);
}
catch (WebPushException exception)
{
Console.WriteLine("Http STATUS code" + exception.StatusCode);
}
After looking at your service worker source, I think you need to move the showNotification call inside the event.waitUntil call. So something like this:
event.waitUntil(self.registration.showNotification(title, options));
However if you're getting notifications on your home network and not your work network, that leads me to believe something on your work network is blocking it.

SignalR negotiate succesfully but fail at start request

I am developing a chat application for our internal application using SignalR in a javascript angularJS client with a (self hosted for the moment) webAPI. This is in a cross domain connection.
using SignalR 2.2.1
using Owin 3.0.1
using Angular 1.5.7 if that's relevant
My problem is whenever I try to establish a connexion with my hub,
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Auto detected cross domain url.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Client subscribed to hub 'chathub'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Negotiating with 'https: localhost:44361/signalr/negotiateclientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: webSockets transport starting.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Connecting to websocket endpoint 'wss: localhost:44361/signalr/connect?transport=webSockets&clientProtocol=1…kAIY9w9Q%3D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&tid=4'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Websocket opened.
the start request fails
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: webSockets transport connected. Initiating start request.
Failed to load resource: the server responded with a status of 500 ()
XMLHttpRequest cannot load https: localhost:44361/signalr/start?transport=webSockets&clientProtocol=1…D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1471436795468. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https: localhost:3000' is therefore not allowed access. The response had HTTP status code 500.
I've tried to pin point this problem for a couple of days now and what've noticed is that in the start request call, the response is missing the 'Access-Control-Allow-Origin' header. What bugs me most is that the negotiate request and the abort request both contains the header
Negotiate Request
Request URL:https: localhost:44361/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=14714 39245326
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:44361
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https: localhost:3000
Cache-Control:no-cache
Content-Type:application/json; charset=UTF-8
Date:Wed, 17 Aug 2016 13:07:29 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Content-Type-Options:nosniff
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNccmFwaGFlbC5tb3JpblxTb3VyY2VcUmVwb3NcVGVhbXdvcmtTb2x1dGlvblxUZWFtd29yay5BcGlcc2lnbmFsclxuZWdvdGlhdGU=?=
but not my start request
Start Request
Request URL:https: localhost:44361/signalr/start?transport=webSockets&clientProtocol=1.5&connectionToken=tR9V6HAxpgmW7r5Ro%2BzJzhUoJdMUcmv7eDv1ZDM%2Fq6yur21LXCZ2Dg1rrNrDGc5VBXQzfanyisyZKOcWNP7SKOl3TsTkBl3luS4I2UnYtdw8biviZ5NtcE1caoXPi3lVHaHs%2FjQnicwGVDlmJdvRzA%3D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1471439245327
Request Method:GET
Status Code:500 Internal Server Error
Remote Address:[::1]:44361
Response Headers
Cache-Control:private
Content-Type:text/html; charset=utf-8
Date:Wed, 17 Aug 2016 13:08:05 GMT
Server:Microsoft-IIS/10.0
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNccmFwaGFlbC5tb3JpblxTb3VyY2VcUmVwb3NcVGVhbXdvcmtTb2x1dGlvblxUZWFtd29yay5BcGlcc2lnbmFsclxzdGFydA==?=
Here is my Startup class
[assembly: OwinStartup(typeof(Teamwork.Api.Startup))]
namespace Teamwork.Api
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration {
EnableJavaScriptProxies = false,
EnableDetailedErrors = true};
map.RunSignalR(hubConfiguration);
});
}
}
}
My hub
namespace Teamwork.Api.Hubs
{
public class ChatHub : Hub
{
public void TransferMessage(string receiver, string message)
{
var name = this.Context.User.Identity.Name;
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.Group(name).AddMessage(name, message);
context.Clients.Group(receiver).AddMessage(receiver, message);
}
public override Task OnDisconnected(bool stopCalled)
{
var name = this.Context.User.Identity.Name;
Clients.All.changeStatus(name, 4);
return base.OnDisconnected(stopCalled);
}
public override Task OnConnected()
{
var name = this.Context.User.Identity.Name;
Clients.All.changeStatus(name, 0);
return Groups.Add(name, name);
}
}
}
I access it using an angularJS service provider that didn't have any problem with until i tried to subscribe to my hub
Service Provider
class ChatServiceProvider implements IChatServiceProvider {
baseUrl: string;
chatHub: HubProxy;
public setBaseUrl(url: string) {
this.baseUrl = url;
}
public $get(
$rootScope: fuse.interfaces.IRootScope
): IChatService {
var self = this;
var connection = $.hubConnection(self.baseUrl);
var chatHub = connection.createHubProxy("chatHub");
function initialize(): JQueryPromise<any> {
connection.logging = true;
return connection.start();
};
return {
chatHub: undefined,
initialize: () => {
return initialize()
},
on: function (eventName, callback) {
chatHub.on(eventName, function (result: any) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
}
}
}
Controller
self.chatService.on("addMessage", function (name: string, message: string) {
this.addMessage(name, message);
})
this.$scope.reply = function (id: string, message: string) {
this.chatService.chatHub.invoke("transferMessage", id, message);
}
this.chatService.initialize()
.done(function (data: HubProxy) {
self.chatService.chatHub = data;
console.log("Connected");
})
.fail(function () { console.log("Failed") });
I tried to add this code to my Global.asax file without any success:
Context.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
var referrer = Request.UrlReferrer;
if (Context.Request.Path.Contains("/signalr") && referrer != null){
Context.Response.AppendHeader("Access-Control-Allow-Origin", referrer.Scheme + ": " + referrer.Authority);
}
I've been looking for 4 days now for a similar issue and i can find none. As i am not proficient with webAPI and HtmlRequest, i may have miss something obvious. If not then any tips/ideas/answers would be greatly appreciated. If anything is missing, tell me and I'll add it as soon as possible.
Thanks to Holly which had a similar problem but I was too dumb to search correctly

Exception when subscribing to exchange streaming notifications

I'm currently working on a project that has me integrating with Exchange. One of the requirements is to monitor mailboxes for new incoming messages and I thought that leveraging a streaming notifications would be a good idea.
I wrote a sample application to get familiar with how to leverage streaming notifications, however I am encountering the following error: The expected XML node type was Element, but the actual type is Text.
The following is the source of the sample application that I wrote:
using Microsoft.Exchange.WebServices.Data;
using System;
using System.Net;
namespace ExampleProgram
{
class Program
{
public static StreamingSubscriptionConnection streamingConnection;
public static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
public static void NewMailSubscriptionDisconnect(object sender, SubscriptionErrorEventArgs args)
{
Exception e = args.Exception;
Console.Write("Disconnect: ");
Console.WriteLine(e.Message);
if (streamingConnection != null && !streamingConnection.IsOpen)
{
streamingConnection.Open();
}
}
public static void NewMailSubscriptionError(object sender, SubscriptionErrorEventArgs args)
{
Exception e = args.Exception;
Console.Write("Disconnect: ");
Console.WriteLine(e.Message);
}
public static void NewMailSubscriptionNotification(object sender, NotificationEventArgs args)
{
Console.WriteLine("New message has arrived");
}
static void Main(string[] args)
{
var exchangeService = new ExchangeService(ExchangeVersion.Exchange2013_SP1);
exchangeService.Credentials = new NetworkCredential("username", "password", "domain");
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.TraceEnablePrettyPrinting = true;
exchangeService.AutodiscoverUrl("username#example.com", RedirectionUrlValidationCallback);
var newMailSubscription = exchangeService.SubscribeToStreamingNotificationsOnAllFolders(EventType.NewMail);
streamingConnection = new StreamingSubscriptionConnection(exchangeService, 30);
streamingConnection.AddSubscription(newMailSubscription);
streamingConnection.OnNotificationEvent += new StreamingSubscriptionConnection.NotificationEventDelegate(NewMailSubscriptionNotification);
streamingConnection.OnSubscriptionError += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(NewMailSubscriptionError);
streamingConnection.OnDisconnect += new StreamingSubscriptionConnection.SubscriptionErrorDelegate(NewMailSubscriptionDisconnect);
streamingConnection.Open();
do { } while (Console.ReadKey(true).Key != ConsoleKey.Escape);
}
}
}
As you can see from the above source, I have tracing turned on. The following is what is yielded from those traces:
EwsResponseHttpHeader
<Trace Tag="EwsResponseHttpHeaders" Tid="17" Time="2015-10-20 17:42:31Z">
HTTP/1.1 200 OK
Transfer-Encoding: chunked
request-id: <redacted>
X-CalculatedBETarget: EXAMPLE-EXCHANGE-01.example.com
X-NoBuffering: 1
X-DiagInfo: EXAMPLE-EXCHANGE-01
X-BEServer: EXAMPLE-EXCHANGE-01
Cache-Control: private
Set-Cookie: exchangecookie=<redacted>; path=/,X-BackEndCookie=<redacted>; expires=Thu, 19-Nov-2015 17:42:30 GMT; path=/ews; secure; HttpOnly
Server: Microsoft-IIS/8.5
X-AspNet-Version: 4.0.30319
Persistent-Auth: true
X-Powered-By: ASP.NET
X-FEServer: EXAMPLE-EXCHANGE-02
Date: Tue, 20 Oct 2015 17:42:30 GMT
</Trace>
EwsResponse
<Trace Tag="EwsResponse"
Tid="15"
Time="2015-10-20 16:52:07Z"
Version="0.0.0.0">
417 <!-- What is this? -->
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<soap11:Header xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<ServerVersionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
MajorVersion="15"
MinorVersion="0"
MajorBuildNumber="1130"
MinorBuildNumber="6"
Version="V2_23"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types" />
</soap11:Header>
<soap11:Body xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/">
<m:GetStreamingEventsResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:GetStreamingEventsResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:ConnectionStatus>OK</m:ConnectionStatus>
</m:GetStreamingEventsResponseMessage>
</m:ResponseMessages>
</m:GetStreamingEventsResponse>
</soap11:Body>
</Envelope>
2 <!-- Not sure what this is either... -->
</Trace>
Exception Detail
Microsoft.Exchange.WebServices.Data.ServiceXmlDeserializationException occurred
HResult=-2146233088
Message=The expected XML node type was Element, but the actual type is Text.
Source=Microsoft.Exchange.WebServices
StackTrace:
at Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read(XmlNodeType nodeType) in C:\Projects\ews-managed-api\Core\EwsXmlReader.cs:line 187
InnerException:
The source of EwsXmlReader.cs can be found at: https://github.com/OfficeDev/ews-managed-api/blob/master/Core/EwsXmlReader.cs
It looks like "something" is prepending 417 and appending 2 to the response from the Exchange server. It's quite obvious to me why the exception is being thrown, there is text data where there shouldn't be. What's not obvious to me, is why that text data is there.
Any ideas?
Transfer-Encoding: chunked
That's the key to this puzzle, you are seeing the "chunks". 417 is a value in hexadecimal for the length of the <Envelope> chunk when you remove the pretty-print formatting. 2 is the final chunk, just whitespace. Chunked transfer formatting is explained here.
I reformatted the XML to remove the white space, You can count off exactly 0x417 = 1047 characters:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><soap11:Header xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><ServerVersionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="15" MinorVersion="0" MajorBuildNumber="1130" MinorBuildNumber="6" Version="V2_23" xmlns="http://schemas.microsoft.com/exchange/services/2006/types"/></soap11:Header><soap11:Body xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/"><m:GetStreamingEventsResponse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"><m:ResponseMessages><m:GetStreamingEventsResponseMessage ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:ConnectionStatus>OK</m:ConnectionStatus></m:GetStreamingEventsResponseMessage></m:ResponseMessages></m:GetStreamingEventsResponse></soap11:Body></Envelope>
Obviously the http transfer is supposed to remove them, your question gives no decent lead why this did not happen. But hopefully a pretty good lead to find the underlying cause. Fun puzzle btw :)

Google Groups Migration C# API Not Working

I'm trying to use the C# Google Groups Migration API and not having much luck.
I have the following code:
public static void Main(string[] args)
{
var body =
#"Received: by 10.143.160.15 with HTTP; Mon, 16 Jul 2007 10:12:26 -0700 (PDT)
Message-ID: NNNN#mail.samplegroup.com
Date: Mon, 16 Jul 2007 10:12:26 -0700
From: ""xxx""
To: ""xxx""
Subject: SUBJECT
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Delivered-To: xxx
This is the body of the migrated email message.";
var bytes = ASCIIEncoding.ASCII.GetBytes(body);
var messageStream = new MemoryStream(bytes);
var auth = new OAuth2LeggedAuthenticator("xxx.com", "xxx", "xxx", "xxx");
var service = new GroupsmigrationService(auth);
service.Key = "xxx";
var request = service.Archive.Insert("xxx", messageStream, "message/rfc822");
request.Upload();
}
...but this results in an Invalid Credentials exception.
I also tried the following:
public static class Program
{
public static void Main(string[] args)
{
var body =
#"Received: by 10.143.160.15 with HTTP; Mon, 16 Jul 2007 10:12:26 -0700 (PDT)
Message-ID: NNNN#mail.samplegroup.com
Date: Mon, 16 Jul 2007 10:12:26 -0700
From: ""xxx""
To: ""xxx""
Subject: SUBJECT
MIME-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Delivered-To: xxx
This is the body of the migrated email message.";
var bytes = ASCIIEncoding.ASCII.GetBytes(body);
var messageStream = new MemoryStream(bytes);
// Register the authenticator.
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
provider.ClientIdentifier = "xxx";
provider.ClientSecret = "xxx";
var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthorization);
// Create the service.
var service = new GroupsmigrationService(auth);
service.Key = "xxx";
var request = service.Archive.Insert("xxx", messageStream, "message/rfc822");
request.Upload();
Console.ReadKey();
}
private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
{
// Get the auth URL:
// IAuthorizationState state = new AuthorizationState(new[] { TasksService.Scopes.Tasks.GetStringValue() });
IAuthorizationState state = new AuthorizationState(new[] { "https://www.googleapis.com/auth/apps.groups.migration" });
state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
Uri authUri = arg.RequestUserAuthorization(state);
// Request authorization from the user (by opening a browser window):
Process.Start(authUri.ToString());
Console.Write(" Authorization Code: ");
string authCode = Console.ReadLine();
Console.WriteLine();
// Retrieve the access token by using the authorization code:
return arg.ProcessUserAuthorization(authCode, state);
}
}
...but that fails with: Backend Error. The inner exception is:
The remote server returned an error: (503) Server Unavailable.
Ideally I'd prefer the to use the 2 Legged Authenticator approach as it doesn't require manual intervention in copying and pasting an auth-key, but right now getting anything to work would be a plus.
Any help gratefully appreciated!
503 error usually indicated that you are hitting the API quota
https://developers.google.com/google-apps/groups-migration/v1/limits
Would you wait a 24 hours period and try to re-run again? The quota resets itself on a daily basics.
Additionally, you should tag your migration related question with google-email-migration and for group migration with google-groups-migration
I had same problem, and asked to google's support team.
In result, we found that this problem reproduce because "Message-ID" header in example has invalid format.
This typo has been fixed at August 12, 2013.
Please try to change Message-ID from NNNN#mail.samplegroup.com to <NNNN#mail.samplegroup.com>.

Categories