I have a client/server application through windows azure relaying.
This works well using a console application for both server and client.
Now I want to use Windows Phone as a client, but for some reason, I cannot call the servicebus.
I can't add a web reference and when targeting the url in a browser I get the following message:
<s:Fault xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</faultcode><faultstring xml:lang="nl-NL">The message with Action 'GET' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</faultstring></s:Fault>
I have entered the following code in the server app.config:
// sb:// binding
Uri sbUri = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "blabla");
var sbBinding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.None);
serviceHost.AddServiceEndpoint(typeof(IMyContract), sbBinding, sbUri);
// https:// binding (for Windows Phone etc.)
Uri httpsUri = ServiceBusEnvironment.CreateServiceUri("https", serviceNamespace, "https/" + "blabla");
var httpsBinding = new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.Transport, RelayClientAuthenticationType.None);
serviceHost.AddServiceEndpoint(typeof(IMyContract), httpsBinding, httpsUri);
And before opening the host, i'm setting the endpoints to discovery mode public.
What else can or do I need to do to make this work with windows phone?
I think you're fairly close. By what I gather you can't add the web reference to your phone project. While that's possible through that path, I wouldn't recommend to make the effort to expose the metadata endpoint through the Relay since you will not use it at runtime. Instead, reference the contract into your Windows Phone project and make a ChannelFactory with BasicHttpBinding and the target address for the BasicHttpRelatBinding endpoint on the service side.
You've got everything else set up right by what I can tell, including having ACS turned off on the listener so that you can use the regular BasicHttpBinding on the phone.
EDIT:
Since that probably wasn't completely clear, here's a service:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class Program : IEcho
{
static void Main(string[] args)
{
var sh = new ServiceHost(new Program(),
new Uri("http://clemensv.servicebus.windows.net/echo"));
sh.Description.Behaviors.Add(
new ServiceMetadataBehavior {
HttpGetEnabled = true,
HttpGetUrl = new Uri("http://localhost:8088/echowsdl")});
var se = sh.AddServiceEndpoint(typeof(IEcho),
new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.None,
RelayClientAuthenticationType.None), String.Empty);
var endpointBehavior = new TransportClientEndpointBehavior(
TokenProvider.CreateSharedSecretTokenProvider("owner", "...key ..."));
se.Behaviors.Add(endpointBehavior);
sh.Open();
Console.WriteLine("Service is up");
Console.ReadLine();
sh.Close();
}
public string Echo(string msg)
{
return msg;
}
}
The contract IEcho is trivial and not shown. What you'll notice is that I have a ServiceMetadataBehavior hanging "off on the side" exposed through localhost that will give you WSDL if you hit that URI. You can use that address with the "Add Web Reference" client in Visual Studio to create the proxy on Windows Phone; that proxy will use BasicHttpBinding on the phone. I just did that and it works as expected in a trivial phone app (with the reference renamed to MySvc)
private void button1_Click(object sender, RoutedEventArgs e)
{
var client = new MySvc.EchoClient();
client.EchoCompleted += OnClientOnEchoCompleted;
client.EchoAsync("foo");
}
void OnClientOnEchoCompleted(object sender, EchoCompletedEventArgs c)
{
this.textBox1.Text = c.Result;
}
Windows Phone doesn’t stand by the sb protocol. So we can’t use NetTcpRelayBinding. We have two options if we want to consume Service Bus in Windows Phone: Use BasicHttpRelayBinding or WebHttpRelayBinding. In either case, we need to disable the default ACS authentication by setting RelayClientAuthenticationType to None: http://msdn.microsoft.com/en-us/library/windowsazure/microsoft.servicebus.relayclientauthenticationtype.aspx. Then on Windows Phone, we can use the built-in BasicHttpBinding to access SOAP services, and use HttpWebRequest to access REST services.
Best Regards,
Ming Xu.
Related
I created Azure Notification Hub and added the server key from Firebase to the section "GCM/FCM" in notification hub. After which, I used the shared access key and notification hub name to create the installation (following the Azure documentation). Here's the code that I used:
[FunctionName("TestFunction")]
public static async Task<IActionResult> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]
HttpRequest req, ILogger log)
{
var deviceUpdate = new DeviceInstallation()
{
installationId = "<myInstallationid>",
pushChannel = "<DeviceTokenGeneratedByFirebase>",
platform = "fcm",
tags = new string[] {"notificationhubtag1"},
};
var responseMessage = new HttpResponseMessage();
try
{
responseMessage = await Put(deviceUpdate);
}
catch
{
log.LogInformation("exception occured");
}
return new OkObjectResult(responseMessage);
}
// Custom API
public static async Task<HttpResponseMessage> Put(DeviceInstallation deviceUpdate)
{
NotificationHubClient hub = new NotificationHubClient(fullAccessConnString, hubName);
Installation installation = new Installation();
installation.InstallationId = deviceUpdate.installationId;
installation.PushChannel = deviceUpdate.pushChannel;
installation.Tags = deviceUpdate.tags;
switch (deviceUpdate.platform)
{
case "mpns":
installation.Platform = NotificationPlatform.Mpns;
break;
case "wns":
installation.Platform = NotificationPlatform.Wns;
break;
case "apns":
installation.Platform = NotificationPlatform.Apns;
break;
case "fcm":
installation.Platform = NotificationPlatform.Fcm;
break;
default:
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
await hub.CreateOrUpdateInstallationAsync(installation);
return new HttpResponseMessage(HttpStatusCode.OK);
}
public class DeviceInstallation
{
public string installationId { get; set; }
public string platform { get; set; }
public string pushChannel { get; set; }
public string[] tags { get; set; }
}
When I run this code, I get a successful message back. The Azure portal itself does not show much information about the no. of devices registered or active devices information in the Azure notification hub. However, I was able to confirm that the installation exists by making a GET request to the installation API directly through this call:
https://<myNotificationHubNameSpace>.servicebus.windows.net/<myHubName>/installations/<myInstallationId>/?api-version=2015-01
This call returned me a 200 OK with the installation I created from the earlier step. The response looked like this:
{"installationId":"<myInstallationId>","pushChannel":"<DeviceTokenGeneratedByFireBase>","pushChannelExpired":false,"platform":"gcm","expirationTime":"9999-12-31T23:59:59.9999999Z","tags":["notificationhubtag1"]}
So, I went to the Azure Notification Hub and sent a test message from the "Test Send" tab and used the tag "notificationhubtag1" in the SendTo tags field. I got back the successful message that said "The Notification was successfully sent to the Push Notification System" and also got the Registration number.
However, I don't see any notifications being sent to the app itself. How can I debug more information about this specific message being pushed. Where did it get pushed?
Is there any way to find more information on the pushed messages, installed devices etc on the notification hub itself? I found an old post about checking logs which said to switch to standard tier instead of free Tier for more information. I have made the switch to standard tier but I don't see any difference in the way overview or activity logs is displayed to me between Free or Standard Tier.
Notification Hubs acts as a bit of a proxy. So the message you saw in the Portal when performing the test send means it did successfully hand off the notification to FCM to be sent and got a success response back from FCM. This also means the device token was valid.
At that point there is no additional data Notification Hubs can provide since it is no longer in the system.
When we've seen issues like this in the past it tends to imply there is something not quite right in the app configuration itself. Likely there is some logic missing for handling the notification intent.
From the code snippet above, it looks like you are creating the installation from some server side piece and not from the application. My assumption is this means you are still working on integrating the Android SDK for Notification Hubs, since the normal flow is to have devices register themselves with the Hub.
We document the full end-to-end steps here: https://learn.microsoft.com/en-us/azure/notification-hubs/notification-hubs-android-push-notification-google-fcm-get-started
I would mostly recommend looking closely at the various code changes necessary on the Android side. Manifest updates and code changes. If you continue to have issues receiving notifications, please feel free to open a support request in the Portal and we can dig deeper into what's going on.
I am trying to obtain the installation id of the client app/device after registering to the backend (web API hosted in Azure and using Notification Hub) for push notifications. There are multiple methods that give an installation id and I am not sure which is the correct one.
As I understand, the installation id is valid as long as the application stays installed on the device, if its deleted and reinstalled a new installation id is assigned to the device is this correct? If not please advise about the life cycle of the installation id.
private async Task SendRegistrationToServerAsync(NSData deviceToken)
{
//this is the template/payload used by iOS. It contains the "messageParam"
// that will be replaced by our service
const string templateBodyAPNS = #"{
""aps"" : {
""alert"" : ""$(messageParam)"",
""mutable-content"": 1
},
}";
var templates = new JObject();
templates["genericMessage"] = new JObject
{
{"body", templateBodyAPNS }
};
// send registration to web api hosted in Azure
var client = new MobileServiceClient(MyApp.App.MobileServiceUrl);
await client.GetPush().RegisterAsync(deviceToken, templates);
//get the installation id (not sure if this is the correct way)
Console.WriteLine("Installation id: " + client.InstallationId.ToString());
}
I think you are right.
According to https://blogs.msdn.microsoft.com/writingdata_services/2016/01/22/adding-push-notification-tags-from-an-azure-mobile-apps-client/#comments:
The installation ID is a GUID that is specific to an installed app on
a given mobile device, to the point that when you uninstall and
reinstall the app on the same device you get a new GUID.
And the installation ID can be obtained from the Mobile client API:MobileServiceClient.InstallationId;
Now I'm using google ads . I followed the step from here(convert OC to C#).And I have add a new adUnitID .It built without error.However.My bannerView didn't display on my test device.Any advice? I know from other forum that google admob will be blocked in some countries, is that true?
in Appdelegate.cs
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window.RootViewController = new XttcViewController();
Window.MakeKeyAndVisible();
MobileAds.Configure("xxx");
return true;
}
in ViewController.cs
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.bannerView = new BannerView(new CGRect(0,100,320,50));
View.AddSubview(this.bannerView);
this.bannerView.AdUnitID = "xxx";
this.bannerView.RootViewController = this;
this.bannerView.LoadRequest(Request.GetDefaultRequest());
}
If you have recently created an AD unit ID(in 24 hours), it may take some time and several AD requests to build up AD resources. Because of this, you may not immediately see the actual presentation. You can use the test unitID. Please note that the test AD runs through the same channels as the actual AD. If the test AD returns, your application is communicating correctly with the network.
The test ID for bannerview in iOS is "ca-app-pub-3940256099942544/2934735716".
If your issue persists even if you use the test ID.You can check for more specific causes from the google support
I started to work with SignalR on Visual Studio 2012, so far I got the basic hang of it, I guided myself through this example (You can browse the code in the page). I decided I wanted to add a REST service to said example, so I added a basic service to it and it worked.
The next step I wanted to take was to add a communication between the service and SignalR, so according to what the example showed to me, I only needed to create a HubConnection through the url in my project (in this case, the example uses the url http:localhost:4200). You can check the WorkerRoleHubConfiguration class, it has a method that has the next line:
return RoleEnvironment.GetConfigurationSettingValue("GUI_URL");
Where GUI_URL is http:localhost:4200.
In my service class then I just added a method with the following:
var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
try
{
HubConnection _connection = new HubConnection(url);
IHubProxy _hub = _connection.CreateProxy("SiteMonitR");
_hub.Invoke("displayResult");
}
catch (Exception ex)
{
error = ex.ToString();
}
But that throws an exception, this one.
I don't undertand why I can get the url in the same way the example does, as I'm doing everything as it's done on the Server class.
The goal I'm trying to achieve is that when an endpoint is accesed and something changes in my system, SignalR notifies to the clients connected to it.
I hope anyone can help me understand what's wrong with my work.
EDIT
I'm adding my ServiceConfiguration.Local.cscfg, my ServiceConfiguration.Cloud.cscfg and ServiceDefinition.csdef files as reference here, I think the problem should be around there but to be honest I got no idea as to why this isn't working.
EDIT 2
I'm getting the following exception at this line var url = RoleEnvironment.GetConfigurationSettingValue("http://localhost:4200");
The exception is:
SEHExcetion occurred. External component has thrown an exception.
The URL is for a GUI - it has to be a web interface for signalr to negotiate the hub connection. In the example, the hub (server) sends updates to connections coming from the configured URL - again a web interface (html page).
The logic to communicate needs to reside in the Server class and be called from the worker role. For example, after making a call to your service in the worker role, then call server.DoSomething("message") to invoke a message to the server. THat code would look something like:
public Class Server
{ ...
public void DoSomething(string message)
{
_hub.Invoke("doSomething", message);
}
...
}
Then in Server.Run() add:
// whenever a DoSomething is called
_hub.On<string>("doSomething", (message) => _hub.Invoke("doSomething", message));
And in SiteMonitRNotificationHub
public class SiteMonitRNotificationHub : Hub
{
...
public void DoSomething(string address)
{
Clients.doingSomething(address);
}
...
}
Finally in the controller script in the web gui:
c.siteMonitorHub
...
.on('doingSomething', function (message) {
c.doSomething(message);
})
and...
this.doSomething= function (message) {
// do something in your web page with message
};
I have made one Application which requires internet connection so that I can display some data in my app.
But when I test my that app in Nokia c1-01 it can't get data from my server and at the same time if I check my app in any other device they are easily connected with internet and I can see my app.
Here is my code:
HttpConnection httpConn = null;
InputStream is = null;
OutputStream os = null;
StringBuffer sb = new StringBuffer();
try {
// Open an HTTP Connection object
httpConn = (HttpConnection) Connector.open(url);
// Setup HTTP Request to POST
httpConn.setRequestMethod(HttpConnection.POST);
httpConn.setRequestProperty("User-Agent",
"Profile/MIDP-2.0 Confirguration/CLDC-1.1");
httpConn.setRequestProperty("Accept_Language", "en-US");
//Content-Type is must to pass parameters in POST Request
httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
os = httpConn.openOutputStream();
os.write(params.getBytes());
/**Caution: os.flush() is controversial. It may create unexpected behavior
on certain mobile devices. Try it out for your mobile device **/
//os.flush();
// Read Response from the Server
//StringBuffer sb = new StringBuffer();
is = httpConn.openDataInputStream();
int chr;
while ((chr = is.read()) != -1) {
sb.append((char) chr);
}
} finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
if (httpConn != null) {
httpConn.close();
}
}
What I have to change in my code so that it can run on my Nokia C1-01?
Two things comes to mind.
The first one is trivial, and has to do with Internet settings on the phone. I don't know the Nokia C1 specifically, but I know that many devices have an Internet setting for the device + another Internet setting for Java. Make sure that the Internet setting for Java is correct. Just because you can use the browser on the phone, doesn't mean that Internet connection works for Java MIDlets.
The second thing you can look into, has to do with the Content-Type property.
I had this issue when I was developing a game that retrived and sent highscores to my webserver, via PHP on the server. I found it rather weird that it worked fine on most our test-phones, while a few had issues.
Outputting the data the phone received back revealed a 404 reply (or something similar, it's been a while).
After consulting another JavaME developer, I learned this:
Some devices send specific instructions to the webserver: "Hello. Gimme some data of type text/plain from data.php please".
If data.php contains a header('Content-type: text/plain'), then all is fine. If not, then the server replies: "Sorry mate, I don't have any text/plain stuff at that address".
This only happens on some devices, because only some devices send that specific a request.
So, whatever Content-Type you define in your setRequestProperty() in the JavaME part, must be the same in your server-side script.
Hope one of those two things helps. :-)