A stored notification channel URI may go stale while my app is inactive -- i.e., stopped, tombstoned or dormant. What is the best practice for updating the channel URI with my web service after a period of inactivity?
Various articles on the web mention "retrieving" the URI in order to send it to the web service. But as far as I can tell, the only way for my app to learn the channel URI is via the ChannelUriUpdated event on HttpNotificationChannel, and raising that event is not under my control. MPNS may have changed the URI while my app was inactive. If the app could not respond to ChannelUriUpdated, the URI would then be stale in both my app and my web service.
Perhaps a channel returned by HttpNotificationChannel.Find is guaranteed to always have an up-to-date channel URI?
General best practice is to request the current channel Uri whenever the app is started. Within the app you should keep track of the last value returned (across application invocations) and if it's changed to upload to your web service.
Please follow this Updated document here. what it does is, it executes a script on insert of the channel uri, it checks if the channel URI exits, if it exists it does not insert the record, else it inserts the record. so, once the channel uri for a device expires, a new channel uri is given to the device in that case, the comparision mismatches and the new channel uri is inserted. by doing that the device is always sent the notification.
Note:- to leverage that functionality, you have to send for insert every time your app starts. hope this helps.
Related
I am using an Onvif-supported camera and am controlling it using onvif wsdl's (specifically ImagingService, Media10, and PTZ). These work great for controlling most aspects of the camera, but there are a few settings that I want to modify that do not seem to be supported by my camera's version of Onvif.
Onvif works by sending soap requests/packets to the camera. However, when I used Wireshark and observed what happens when I use the software the camera came with, I noticed it works by sending http GET/POST requests containing FormUrlEncoded messages, and one of the fields is labelled session, presumably the session ID for the connection. I was able to recreate the message that the camera's software sends, send it, and confirm that my settings change. However, whenever a new session starts (different ID), it no longer works, and my http response contains:
{"error":{"code":287637505,"message":"Invalid session in request data!"},"result":false}
In other words, hard coding the session Id that I got through wireshark was the only way I could get it to work, but as soon as the session changes it no longer works. I was wondering if there was a way to easily get the session ID, store it as a variable, and then just place it within my messages. I would hope this would be possible either through the HttpClient, or any of the three Onvif clients I am using (MediaClient, ImagingClient, or PTZClient).
I have tried searching through many of the methods/fields in each of the clients above, creating HttpWebRequests, looking through the response messages for GET & POST, looking around where the login credentials are kept, and creating a Cookie with the info.
The way I go about setting everything up is rather simple:
private static readonly HttpClient httpClient = new HttpClient();
var msg = $"{{\"method\":\"configManager.setConfig\",\"params\":{{\"name\":\"VideoInExposure\",\"table\":" +
$"[[{{\"AntiFlicker\":2,\"Compensation\":50,\"DoubleExposure\":0,\"Gain\":50,\"GainMax\":2,\"GainMin\":0," +
$"\"GlareInhibition\":0,\"Iris\":50,\"IrisAuto\":true,\"IrisMax\":30,\"IrisMin\":0,\"Mode\":4,\"RecoveryTime\":900," +
$"\"SlowAutoExposure\":50,\"SlowShutter\":false,\"SlowSpeed\":30,\"Speed\":0,\"Value1\":250,\"Value2\":250," +
$"\"WideDynamicRange\":0,\"WideDynamicRangeMode\":0}}}]],\"options\":[]}},\"id\":6123,\"session\":\"4ec9a21aac415eead620ab163141fa03\"}}";
var response = await httpClient.PostAsync("http://192.168.100.233/RPC2", new StringContent(msg, Encoding.UTF8, "application/x-www-form-urlencoded"));
Where the portion labeled session at the end of the message is the string that I need to obtain.
I was hoping this property would be stored somewhere accessible, either in the client, or within a response if I just do a simple GET command, but I have not yet found this to be the case. Any help is greatly appreciated!
edit: I have also tried getting this value from the soap commands that Onvif already uses, with no luck so far. But if there is a way to do it that way I am very open to it.
I am overriding both DidReceiveRemoteNotification and ReceivedRemoteNotification and leaving them empty in an attempt to prevent my remote notifications to push automatically, but it does not seem to help. Because every time I send a postman request for the notification, they still show up.. How can i prevent the notification from pushing until the app has met the necessary requirements (user is signed inn) ?
When your app starts up, register or unregister, as soon as you know the app state
Unregister:
UIApplication.SharedApplication.UnregisterForRemoteNotifications();
Register:
UIApplication.SharedApplication.RegisterForRemoteNotifications();
This is the first time I'm using Azure Notification Hubs and I'm having some trouble getting it working properly with my application.
The part I'm stuck on (at the moment) is registering my device with the notification hub. I'm using the backend method to do the registration ... that is, I'm creating an Installation object and using the CreateOrUpdateInstallationAsync method to register the device via my Web API. I'm only testing it at this stage so I'm hitting my API endpoint with dummy data via Postman.
When I step through my code, I'm getting the following error when I execute CreateOrUpdateInstallationAsync ...
The remote server returned an error: (404) Not Found. Entity does not
exist.TrackingId:203cba37-007d-4dcb-ae25-ced33fa012aa_G1,TimeStamp:2/4/2018
10:24:02 PM
I've tested that I am connecting to the Notification Hub correctly by calling GetAllRegistrationsAsync. This returns an empty list (expected) and no error ... so I have my endpoints set up correctly. I'm wondering if there is a problem with my dummy data? For the installation Id, I've just created a random GUID (Guid.NewGuid). The Device ID and Push Notification Handle are random numbers and letters. And I'm testing this for the Android platform (NotificationPlatform.Gcm).
Has anyone seen this error before and know what it means? Am I able to just use random data for testing purposes (I'm only interested in registering devices at this stage) or do I need legitimate data (real device id's, etc)?
Thanks in advance.
The CreateOrUpdateInstallationAsync method would essentially invoke the REST API Create or Overwrite an Installation. When you register with a notification hub from your custom backend using the Installation, the core code would look like as follows:
NotificationHubClient hubclient = NotificationHubClient.CreateClientFromConnectionString(listenConnString, hubName);
await hubclient.CreateOrUpdateInstallationAsync(installation);
Note: You could install the Microsoft.Azure.NotificationHubs package for back end operations.
For a simpler way, I just created a console application and test this operation as follows:
Note: I just created a new Azure Notification Hub and did not set any notification settings. And I set a GUID as the InstallationId and a random string as the PushChannel, the rest operation could work as expected.
And I could retrieve the previous added registration as follows:
Has anyone seen this error before and know what it means? Am I able to just use random data for testing purposes (I'm only interested in registering devices at this stage) or do I need legitimate data (real device id's, etc)?
The operation could work on my side, I would recommend you debug your application and leverage fiddler to capture the network traces to narrow this issue. Moreover, you could follow Registration management for more details about registering devices with azure notification hubs.
Ok, it turns out that I had the wrong value for Hub Name when instantiating the NotificationHub object using NotificationHubClient.CreateClientFromConnectionString. I was using the namespace, instead of the hub name (visible on the Overview tab in the Azure Portal).
I am getting the EWS URL as below:
var response = myAutodiscoverService.GetUserSettings(
"userA#domain.com",
UserSettingName.ExternalEwsUrl,
UserSettingName.InternalEwsUrl,
UserSettingName.EwsSupportedSchemas);
string settingValue;
if (response.TryGetSettingValue(UserSettingName.ExternalEwsUrl, out settingValue)
|| response.TryGetSettingValue(UserSettingName.InternalEwsUrl, out settingValue))
{
// If ExternalEwsUrl is not returned in the response,
// we consider InternalEwsUrl for auto-discover
string ewsurl = settingValue;
}
Now, I am caching this ewsurl I get with this request as recommended since auto-discovery is really slow. What happens when this ewsurl expires (because let's say user's mailbox was moved to a different endpoint). What error should I expect in order to implement a failure mechanism to get the new updated ews url?
Edit: I am using the ews url to subscribe for new mail events on EWS using ExchangeService.SubscribeToPushNotifications So I have another question, suppose if the ews url was changed after user subscribed for notifications, will I get a notification for that user for a new mail event on the callback url of my application?
I seem to recall the ROT from MSFT was you should re-autodiscover every 24 hours, but I've not seen anything recently. As to the Push notifications: since there is a "heartbeat" facility in Push notifications, if you miss two heartbeats in a row, it's safe to say you should tear down the subscription and re-subscribe, which to be safe, implies re-autodiscovery. Of course with O365, since the EWS URL seems (for now) to always be the same, re-autodiscovery is less of a concern.
I've got several web-services: asmx,wcf. At couple of them there are some methods, which take a lot of time for processing, but size of input data for these methods are small and it takes not much time to transfer on the wire. I want move to not sync model. Client passes data to service, service answers that data transfer was correct and process it at background thread witout connection with client. So agter transfering connection should be closed. IS it possible? Can u help me with articles or may be just google request.
John is right - Once you close an http connection, it is done. You can't get back to the same process.
So if you can use another technology that allows duplex on one connection (e.g. WCF), do it!
However,
if you have no choice but to use webservices,
here are three ways to make it work. You may get timeouts on any of them.
Option 1:
Forget the part about 'client answers data was correct.' Just have each thread make its request and wait for the data.
Option 2:
Now, assuming that won't work and you must do the validation, this way requires the client to make 2 requests.
First request: returns valid/invalid.
Second request: returns the long-running results.
Variation of option 2:
If you have timeout problems, you could have the first request generate a GUID or unique database key and start another process, passing it this key, and return the key to the client. (if you can get the server to allow you to start a process - depends on security settings/needs - if not you may be able to start an async thread and have it keep running after the websvc one ends?) The process will do the long task, update the row in the database w/ the unique id when finished, revealing the results plus a 'done' flag. The second request by the client could always return immediately and if the processing is not done, return that, if it is, return the results. The client will repeat this every 5 sec or so until done.
Hacks, I know, but we don't always have a choice for the technology we use.
Don't do this with ASMX web services. They weren't designed for that. If you must do it with ASMX, then have the ASMX pass the data off to a Windows Service that will do the actual work, in the background.
This is more practical with WCF.
We have been writing stuff to interact with the UK gov website and the way they handle something similar is that you send your request and data to the server and it responds saying, roughly, "thanks very much - we're processing it now, please call back later using this id" - all in an XML message. You then, at some point later, send a new http request to the service saying, essentially, "I'm enquiring about the status of this particular request id" and the server returns a result that says either it has processed OK, or processed with errors, or is still processing, please try again in xx seconds.
Similar to option 2 described previously.
It's a polling solution rather than a callback or 2 way conversation but it seems to work.
The server will need to keep, or have access to, some form of persistent table or log for each request state - it can contain eg, the id, the original request, current stage through the workflow, any error messages so far, the result (if any) etc. And the web service should probably have passed the bulk of the request off to a separate Windows service as already mentioned.