Subscribing to Azure Push Notification service in Xamarin Forms - azure

I tried to integrate with Push Notifications to my forms application. Azure messaging component is used for achieving this.
Below is the code i am using. I am getting the trigger to RegisteredForRemoteNotifications method. But RegisterNativeAsync method doesn't seem to be doing the job.
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var push = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(push);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
const UIRemoteNotificationType not = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(not);
}
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
Hub = new SBNotificationHub(conStirng, NotifHubPath);
Hub.UnregisterAllAsync(deviceToken, (error) =>
{
//Get device token
var id = deviceToken.ToString();
var tag = "username";
var tags = new List<string> { tag };
Hub.RegisterNativeAsync(id, new NSSet(tags.ToArray()), (errorCallback) =>
{
if (errorCallback != null)
{
//Log to output
}
});
});
}
What am i doing wrong here? How can i confirm if the Register function is success or failure.?

You need to check if the error from the response of the register method is null or not. if it is null means the it is a success.
var hub = new SBNotificationHub (cs, "your-hub-name");
hub.RegisterNativeAsync (deviceToken, null, err => {
if (err != null)
Console.WriteLine("Error: " + err.Description);
else
Console.WriteLine("Success");
});
In the case of windows universal apps we can check the registrationId property of the response.
private async void InitNotificationsAsync()
{
var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
var hub = new NotificationHub("<hub name>", "<connection string with listen access>");
var result = await hub.RegisterNativeAsync(channel.Uri);
// Displays the registration ID so you know it was successful
if (result.RegistrationId != null)
{
var dialog = new MessageDialog("Registration successful: " + result.RegistrationId);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}

Related

Request body goes missing when application is deployed to Azure

I have a net6.0 Razor pages app that is running fine locally, but doesn't work when deployed to Azure. It seems that POST bodies are going missing.
Here's some middleware...
public async Task Invoke(HttpContext context)
{
_logger.LogInformation("BodyLogger");
if (!context.Request.Body.CanSeek)
{
context.Request.EnableBuffering();
}
if (context.Request.Method == "POST")
{
_logger.LogInformation("POST cl=" + context.Request.ContentLength.ToString());
try
{
_logger.LogInformation("BodyLogger try");
string body = "";
context.Request.Body.Position = 0;
using (var reader = new StreamReader(context.Request.Body, leaveOpen: true))
{
_logger.LogInformation("BodyLogger using");
body = await reader.ReadToEndAsync();
}
context.Request.Body.Position = 0;
_logger.LogInformation($"BODY ok (length {body?.Length ?? 0})" + (body ?? "(null)"));
}
catch (Exception e)
{
_logger.LogError("BODY error " + e.Message);
throw;
}
}
await _next.Invoke(context);
}
...and what appears in ApplicationInsights.
What's going on?!
Updage
Even more strangely: it still doesn't work if it's deployed to a different Azure Web App resource, and this middleware
app.Use(async (HttpContext context, RequestDelegate next) =>
{
if (context.Request.Path == "/post")
{
if (!context.Request.Body.CanSeek)
{
context.Request.EnableBuffering();
}
//context.Request.Body.Position = 0;
context.Request.Body.Seek(0, SeekOrigin.Begin);
string body = "";
using (var reader = new StreamReader(context.Request.Body, leaveOpen: true))
{
body = await reader.ReadToEndAsync();
}
//context.Request.Body.Position = 0;
context.Request.Body.Seek(0, SeekOrigin.Begin);
await context.Response.WriteAsJsonAsync("The body was: " + body);
return;
}
await next.Invoke(context);
});
works both as the first and the last middleware.
I've noticed that absent from the ApplicationInsights logs are the Kestrel messages
Connection id "0HMOAORGGN3ES", Request id "0HMOAORGGN3ES:00000003": started reading request body.
Connection id "0HMOAORGGN3ES", Request id "0HMOAORGGN3ES:00000003": done reading request body.
It turns out that in some cases my custom ITelemetryInitializer for ApplicationInsights (turned off in development) was reading the request body.

Fetch API Doesn't send data on first call - NestJs

I have an API in NestJs which is not sending data on the first hit. However, on hitting it again it sends the desired data. I am guessing the API returns before the internal processing is done.
How to stop this. Is sleep a good option for this?
Or is there any other way to do this?
#Post("load")
#UseGuards(AuthGuard("jwt"))
async load(#Req() body: any)
{
const organizationId = body.user.organizationId;
const userId = body.user.userId;
if ("brandIds" in body.body)
{
await this.userService.onBoardUser(userId);
}
var settings = await this.settingsService.fetchLayout(organizationId, "home");
settings.forEach(async (element) =>
{
var parsedElement = JSON.parse(JSON.stringify(element));
var innerContent = await this.fetchContent(parsedElement.method, organizationId, userId);
var template = parsedElement.content[0];
let formattedItem = {};
innerContent.forEach((item) =>
{
try
{
formattedItem = template;
Object.keys(template).forEach((key) =>
{
if (template[key]!= "" && key != "type")
{
formattedItem[key] = eval(template[key]);
}
});
parsedElement.content.push(formattedItem);
formattedItem = null;
}
catch(err)
{
}
});
this.response.data.push(parsedElement);
innerContent = null;
template = null;
formattedItem = null;
parsedElement = null;
});
return(this.response);
}
looks like your main problem here is that your using async/await inside foreach which isnt working.
Use it like this:
for (const setting of settings) {
... your async code here.
}

Receive messages from Azure IotHub in xamarin .netstandard

I am developing the xamarin app in .netStandard 2.0 using visual studio 2019.I have a problem to received data from iothub.I able to send data from xamarin app to iot hub but unable to received data from azure iothub.
Liberies
Microsoft.Azure.Device (1.20.0)
Microsoft.Azure.Device.Client (1.24.0)
private const string DeviceConnectionString = "HostName=[your hostname];DeviceId=[your DeviceId];SharedAccessKey=[your shared key]";
public async Task Start()
{
try
{
DeviceClient deviceClient =
DeviceClient.CreateFromConnectionString(DeviceConnectionString, TransportType.http1);
await SendEvent(deviceClient);
await ReceiveCommands(deviceClient);
}
catch (Exception ex)
{
Debug.WriteLine("Error in sample: {0}", ex.Message);
}
}
async Task SendEvent(DeviceClient deviceClient)
{
string dataBuffer;
dataBuffer = "Hello Iot";
Message eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer));
await deviceClient.SendEventAsync(eventMessage);
}
async Task ReceiveCommands(DeviceClient deviceClient)
{
Message receivedMessage;
string messageData;
while (true)
{
receivedMessage = await deviceClient.ReceiveAsync();
if (receivedMessage != null)
{
messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
txtblkMessages.Text = messageData + "\n" + txtblkMessages.Text;
await deviceClient.CompleteAsync(receivedMessage);
}
await Task.Delay(TimeSpan.FromSeconds(1));
}
}

How do I use the rabbitmq in my .net core web

As the title suggests,Examples on the official website are console project but is it really impossible to apply to asp.net core web?
My web project as a consumer or producer but does not output received information,But the rabbitmq page console displays the queue messages sent,so What are consumers or producer in the actual production environment?windows server?console?
this is my api code:
[HttpGet]
public ActionResult sendMgs()
{
string message = string.Empty;
//var uri = new Uri("amqp://192.168.150.129:5672");
var factory = new ConnectionFactory()
{
UserName = "admin",
Password = "admin",
Port=5672,
HostName= "192.168.150.129",
RequestedHeartbeat = 0,
VirtualHost= "/vhost_mmr"
//Endpoint = new AmqpTcpEndpoint(uri)
};
using (var connection=factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue:"hello",
durable:false,
exclusive:false,
autoDelete:false,
arguments:null);
message = "Hello World";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "",
routingKey:"hello",
basicProperties:null,
body:body);
}
}
return Json(new {message = message });
}
and this my mvc web code:
public IActionResult MqTest()
{
System.Diagnostics.Debug.Write("test begin:");
GetQueueMsg();
return View();
}
public void GetQueueMsg()
{
var factory = new ConnectionFactory()
{
UserName = "admin",
Password = "admin",
Port = 5672,
HostName = "192.168.150.129",
RequestedHeartbeat = 0,
VirtualHost = "/vhost_mmr"
};
using (var connection = factory.CreateConnection())
{
using (var channel =connection.CreateModel())
{
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var msg = Encoding.UTF8.GetString(body);
ViewBag.msg = msg;
System.Diagnostics.Debug.Write("test:" + msg);
};
var ret = channel.BasicConsume(queue: "hello",
autoAck: true,
consumer: consumer);
}
}
}

Web API 2 - block all external calls

Is it possible to block all calls to my web api that are not coming from the web-site itself?
I mean if my MVC app runs at : http://www.domain.com and the web api at http://www.domain.com/api/service, I want the web api to accept calls only from current application only. No external calls allowed.
I will guess maybe a message handler will be the best in this case?
Create a Controller for error page and catch all garbage requests like this:
config.Routes.MapHttpRoute("block", "{*something}", new { controller = "Error", action = "Get" });
You should implement token authorization using a delegating handler.
public class AuthorizationHeaderHandler : DelegatingHandler
{
public AuthorizationHeaderHandler(HttpConfiguration httpConfiguration)
{
//set the inner handler
InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
IEnumerable<string> apiKeyHeaderValues = null;
if (request.Headers.TryGetValues("X-ApiKey", out apiKeyHeaderValues))
{
var apiKeyHeaderValue = apiKeyHeaderValues.First();
//based on the api-key get username whose session is stil valid.
var username = //code to get user based on apiKeyHeaderValue;
if (!string.IsNullOrEmpty(username))
{
var usernameClaim = new Claim(ClaimTypes.Name, username);
var identity = new ClaimsIdentity(new[] {usernameClaim}, "ApiKey");
var principal = new ClaimsPrincipal(identity);
Thread.CurrentPrincipal = principal;
}
}
else
{
//You don't have an ApiKey from the request... can't proceed
var response = request.CreateResponse(HttpStatusCode.Forbidden,
new {Message = "You are not Authorized to access that resource"}); //new HttpResponseMessage(HttpStatusCode.Forbidden);
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
return base.SendAsync(request, cancellationToken);
}
}
You can then register the handler in the WebApiConfig
public class WebApiConfig
{
public static void Init(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints:null,
handler: new AuthorizationHeaderHandler(GlobalConfiguration.Configuration)
);
}
}
you can then setup your login controller to authorize a user and assign then a token
public class UserController : ApiController
{
public async Task<HttpResponseMessage> Login([FromBody] UserDTO userDTO)
{
// first perform user authentication.
// clear all existing tokens for this authorized user
//create security token and save token of current user
//You can store this in a database and use a repository to create these.
// Tokens can be guids.
// await token creation
return Request.CreateResponse(HttpStatusCode.OK, new {LogingResult = result, token = token});
}
}
Once that user has the token, it can be used for Api requests by adding to the request header. In Angularjs it can take the following form.
'use strict';
(function () {
angular.module('App', ['ngRoute', 'ngCookies']);
//interceptor for server calls
var httpInterceptor = function ($q, $window, $location) {
return function(promise) {
var success = function(response) {
return response;
};
var error = function(response) {
if (response.status === 403) {
$location.url('/login');
}
return $q.reject(response);
};
return promise.then(success, error);
};
}
httpInterceptor['$inject'] = ['$q', '$window', '$location'];
angular.module('App').factory('httpInterceptor', httpInterceptor);
var api = function ($http, $cookies) {
return {
init: function (token) {
$http.defaults.headers.common['X-ApiKey'] = token || $cookies.token;
}
};
}
api['$inject'] = ['$http', '$cookies'];
angular.module('App').factory('api', api);
})();
Yes this is definitely possible. You have to create a custom handler and filter for the RemoteIpAddress found in the request. Here's an implementation using Owin Self-Host:
public class CustomerHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request?.GetClientIpAddress() != "127.0.0.1")
{
return await Task.FromResult(request.CreateResponse(HttpStatusCode.Unauthorized));
}
return await base.SendAsync(request, cancellationToken);
}
}
public static class HttpReqestMessageExtension
{
public static string GetClientIpAddress(this HttpRequestMessage request)
{
if (!request.Properties.ContainsKey("MS_OwinContext")) return null;
dynamic owinContext = request.Properties["MS_OwinContext"];
return owinContext.Request.RemoteIpAddress;
}
}
If you where using ASP.Net then you would use the appropriate key => MS_HttpContext
Now you simply add this to the startup of your Api:
var config = new HttpConfiguration();
config.MessageHandlers.Add(new CustomerHandler());

Resources