How do I handle calling windows azure mobile services and detecting no connection ? - azure

I have the code for using HttpClient below but now I want to use Windows Azure Mobiles Services.. My app was not published because they said I am not checking for a connection.. What is a simple way to do this ?
private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
SystemTray.ProgressIndicator = new ProgressIndicator();
//try to ping service before getting high scores
try
{
SetProgressIndicator(true);
SystemTray.ProgressIndicator.Text = "Loading...";
GetHighScores(); //?????????
// HttpClient httpClient = new HttpClient();
// HttpResponseMessage response = await httpClient.GetAsync("http://punkoutersoftware.azurewebsites.net/api/drunkmeterscore");
// response.EnsureSuccessStatusCode();
SetProgressIndicator(false);
}
catch (HttpRequestException e)
{
MessageBox.Show("High Scores not available at the moment");
}
}
private async void GetHighScores()
{
try
{
scores = await scoreTable.OrderByDescending(x => x.Score).ToCollectionAsync();
}
catch (MobileServiceInvalidOperationException e)
{
MessageBox.Show(e.Message, "Error loading items", MessageBoxButton.OK);
}
ListItems.ItemsSource = scores;
}

I doubt the verification process tests with an unresponsive Azure Mobile Services. They're likely testing with no data connection. You can check for a data connection before doing any operation that might need a data connection like this:
if(!DeviceNetworkInformation.IsNetworkAvailable)
{
// inform user to get a data connection
}

Related

Can I use a basic Web App in Azure to just define a SignalR hub with AZ SignalR Service and use other apps as clients to communicate between them

I have been struggling with this for few days so I am asking whether what I am trying to do is possible.
Basically I am experimenting things with signalR in Azure. I am using the latest version of SignalR NuGet.
I have a small Web App defining a simple signalR hub I want to access via a Azure SignalR Service.
I then have a couple of apps which communicate via hub in the signalR service.
I have various issues.
Getting the hub to load on the AZ SignalR Service. It does not work all the time. Complaining about Serverless/Default settings...
2023-02-16T14:05:25.034917571Z info: Microsoft.Azure.SignalR.Connections.Client.Internal.WebSocketsTransport[1]
2023-02-16T14:05:25.034960072Z Starting transport. Transfer mode: Binary. Url: 'wss://nmg-opus-common-inventory-dev-sigr.service.signalr.net/server/?hub=myhub&cid=9e64b380-b752-4175-8fd2-215a2b62139d'.
2023-02-16T14:05:25.057819457Z info: Microsoft.Azure.SignalR.Connections.Client.Internal.WebSocketsTransport[11]
2023-02-16T14:05:25.057859557Z WebSocket closed by the server. Close status NormalClosure.
2023-02-16T14:05:25.057865857Z info: Microsoft.Azure.SignalR.ServiceConnection[24]
2023-02-16T14:05:25.057870457Z Connection to service '(Primary)https://nmg-opus-common-inventory-dev-sigr.service.signalr.net(hub=MyHub)' handshake failed, probably caused by network instability or service restart. Will retry after the back off period. Error detail: Azure SignalR Service is in serverless mode, server connection is not allowed.. Id: 9e64b380-b752-4175-8fd2-215a2b62139d
2023-02-16T14:05:25.057875657Z info: Microsoft.Azure.SignalR.Connections.Client.Internal.WebSocketsTransport[6]
2023-02-16T14:05:25.057880257Z Transport is stopping.
2
On the client side, it seems that the connection succeeds if the service is set to Serverless mode.
Once connected, my call to join a group just hang and never returns. The connection happens after I click an element (div) on a blazor page.
So I am not sure why something so simple does not work.
here is my very simple hub :
public class MyHub : Hub
{
public async Task SendMessage(string groupName, string message)
{
await Group(groupName).SendAsync("ReceiveMessage", message);
}
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
public async Task LeaveGroup(string groupName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
public override async Task OnConnectedAsync()
{
await Clients.Client(Context.ConnectionId).SendAsync("Connected", Context.ConnectionId);
}
}
here is the classic startup method for the app defining hub
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAzureAppConfiguration();
services.AddSignalR(e => { e.MaximumReceiveMessageSize = 10240000; });
string SignalRURLHub = Configuration.GetValue<string>("Resources:SignalR:Inventory:ConnectionString");
services.AddSignalR().AddAzureSignalR(SignalRURLHub);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAzureAppConfiguration();
app.UseRouting();
var SignalRHubName = $"/{Configuration.GetValue<string>("Resources:SignalR:HubName")}";
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MyHub>(SignalRHubName);
});
}
}
Code from the client applications Initializing the connection and starting it.
protected HubConnection _connection;
private readonly string groupName;
protected ClientHandler(string connectionString, string hubName, string groupName, string userId = null)
{
var serviceUtils = new ServiceUtils(connectionString);
var url = GetClientUrl(serviceUtils.Endpoint, hubName);
_connection = new HubConnectionBuilder()
.WithUrl(url
, option =>
{
option.AccessTokenProvider = () =>
{
return Task.FromResult(serviceUtils.GenerateAccessToken(url, userId));
};
})
.WithAutomaticReconnect(new AlwaysRetryPolicy())
.ConfigureLogging(logging =>
{
logging.SetMinimumLevel(LogLevel.Trace);
logging.AddConsole();
})
.Build();
this.groupName = groupName;
_connection.Reconnected += JoinGroup;
_connection.On("Connected", new[] { typeof(string) }, OnInitialConnection);
}
private string GetClientUrl(string endpoint, string hubName)
{
return $"{endpoint}/client/?hub={hubName}";
}
private async Task JoinGroup(string contextId)
{
try
{
await _connection.InvokeAsync("JoinGroup", groupName); //JoinGroup is C# method name
}
catch (Exception e)
{
}
}
// Called separately after the ClientHandler object is created.
public async Task StartAsyncWithRetry(CancellationToken cancellationToken = default)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
await _connection.StartAsync()
.ContinueWith(res =>
{
_connection.InvokeAsync("JoinGroup", groupName);
});
if (_connection.State == HubConnectionState.Disconnected)
{
await Task.Delay(GetRandomDelayMilliseconds());
continue;
}
return;
}
catch (Exception e)
{
//throw;
//cancellationToken.
await Task.Delay(GetRandomDelayMilliseconds());
}
}
}
I have tried tweaking various setting in Azure, in my apps, changed my code from synch to async...
I must be missing something ... I've found lot of post but many of them were out of date. Also tried my luck with ChatGPT ...

Application Insights + Azure Service Bus - Capture message from the bus in dependency tracking

I am looking into how the app insights work with different types of dependencies. I have a question on using the AppInsights ASP Net Core sdk with Messaging Service Bus sdk.
How can I capture messages to service bus while sending or receiving using this sdk in dependency? I understand that this is not something we would like to log all the time and I will make it configurable.
Thanks
You can create your own sender and implement the desired logic inside the SendMessageAsync method:
public class TelemetryEnabledServiceBusSender : ServiceBusSender
{
private readonly TelemetryClient telemetryClient;
internal TelemetryEnabledServiceBusSender(ServiceBusClient client, string topic, TelemetryClient telemetryClient) : base(client, topic)
{
this.telemetryClient = telemetryClient;
}
public override async Task SendMessageAsync(ServiceBusMessage message, CancellationToken cancellationToken = default)
{
telemetryClient.TrackTrace(message.Body.ToString());
await base.SendMessageAsync(message, cancellationToken);
}
}
use it like this:
var serviceBusSender = new TelemetryEnabledServiceBusSender(serviceBusClient, serviceBusData.Topic, telemetryClient);
await serviceBusSender.SendMessageAsync(message);
Logging processed messages is even simpler and can be done using the ServiceBusProcessor
serviceBusProcessor.ProcessMessageAsync += ProcessMessageAsync;
...
private async Task ProcessMessageAsync(ProcessMessageEventArgs arg)
{
telemetryClient.TrackTrace(arg.Message.Body.ToString());
...
}
Adding my approach as an answer here as it is too long to comment.
var telemetry = new DependencyTelemetry(
"Azure Service Bus",
_serviceBusClient.FullyQualifiedNamespace,
"ServiceBusReceiver.Receive",
string.Empty
);
using var operation =
_telemetryClient.StartOperation(telemetry);
try
{
var receivedMessage = await _serviceBusReceiver.ReceiveMessageAsync();
if (receivedMessage?.Body is not null)
{
message = receivedMessage.Body.ToString();
telemetry.Data = message;
// do something
}
telemetry.Success = true;
//Consider set telemetry duration
}
catch (Exception e)
{
// log exception
_telemetryClient.TrackException(e);
telemetry.Success = false;
throw;
}
finally
{
_telemetryClient.TrackTrace("Done");
_telemetryClient.StopOperation(operation);
}
Thanks to #Peter Bons

Azure Mobile App OAuth with API Controller

Using above service with Xamarin form, I have enabled authentication with OAuth (Microsoft and Google) at server level.
Call from Swagger works fine. However I'm getting 401 error accessing this via the app. This neither works for TableController nor APIController. I'm not using EasyTables. Following is my code.
public async Task<bool> AuthenticateAsync()
{
bool success = false;
try
{
if (user == null)
{
user = await ItemManager.DefaultManager.CurrentClient.LoginAsync(this, MobileServiceAuthenticationProvider.MicrosoftAccount);
Constants.MobileToken = user.MobileServiceAuthenticationToken;
}
success = true;
}
catch (Exception ex)
{
CreateAndShowDialog(ex.Message, "Authentication failed");
}
return success;
}
public async Task<ObservableCollection<Item>> GetItemsAsync(bool syncItems = false)
{
try
{
IEnumerable<Item> items = await itemTable
.ToEnumerableAsync();
return new ObservableCollection<Item>(items);
}
catch (MobileServiceInvalidOperationException msioe)
{
Debug.WriteLine(#"Invalid sync operation: {0}", msioe.Message);
}
catch (Exception e)
{
Debug.WriteLine(#"Sync error: {0}", e.Message);
}
return null;
}
I tried using rest service client, but not sure how to pass the authentication header. As I seen by Swagger, its actually sending via cookie AppServiceAuthSession. How should it be done via Xamarin Forms?
public ItemManager(IRestService service)
{
restService = service;
}
public Task<List<Item>> GetTasksAsync()
{
return restService.RefreshDataAsync();
}
I read that the token we must supply as the 'X-ZUMO-AUTH' is not the access token that provider send back to us; it is the token that the mobile service backend sends back. How we suppose to retrieve this token? And I don't see Swagger sending X-Zumo-Auth header.
Following is my Rest Service initialization :
public RestService()
{
client = new HttpClient(new LoggingHandler(true));
client.MaxResponseContentBufferSize = 256000;
client.DefaultRequestHeaders.Add("x-access_type", "offline");
client.DefaultRequestHeaders.Add("x-zumo-auth", Constants.MobileToken);
client.DefaultRequestHeaders.Add("ZUMO-API-VERSION", "2.0.0");
}
public async Task<List<Item>> RefreshDataAsync()
{
Items = new List<Item>();
var uri = new Uri(string.Format(Constants.RestUrl, string.Empty));
try
{
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<List<Item>>(content);
}
}
catch (Exception ex)
{
Debug.WriteLine(#" ERROR {0}", ex.Message);
}
return Items;
}
EDIT
After enabling the server logging - Azure service is actually throwing 404 error. And this only happens if I enable the custom authorization on the server.
After debugging the code, I notice following difference between authentication handled by both Mobile App vs Swagger :
Mobile App sets the Authentication Type as Federation, but Swagger is setting it correctly as microsoftaccount
And this makes the ID different as well :
I must not be passing the token correctly here.
So what I figured out so far is that I need to pass the header X-ZUMO-AUTH with the current user token to make it work.
And handle this header in the API code to make retrieve user details
//Try to retrieve from header if available
actionContext.Request.Headers.TryGetValues("x-zumo-auth", out auth_token);
if (auth_token !=null)
{
try
{
string urlPath = string.Concat(new Uri(actionContext.Request.RequestUri, actionContext.Request.GetRequestContext().VirtualPathRoot).AbsoluteUri, ".auth/me");
var result = Get<List<AzureUserDetail>>(HttpWebRequest.Create(urlPath), auth_token.FirstOrDefault(), null)?.FirstOrDefault();
userID = result.User_Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Val;
}
catch
{
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.NotAcceptable);
}
}

Why does HttpClient PostAsJsonAsync exit Azure Web Job without running code after it?

I have an Azure Web Job built using the Azure SDK whose only job is to call a web service (Web API) and then log a response based on the return value (a class). The problem is that as soon as it calls the HttpClient PostAsJsonAsync method to call the service, it exits out of the web job without executing any of the response handling. My code is:
public class Result
{
// Properties ---------------------------------------------------------
public bool Success { get; set; }
public string Error { get; set; }
}
public class Functions
{
// This function will be triggered based on the schedule you have set for this WebJob
// This function will enqueue a message on an Azure Queue called queue
[NoAutomaticTrigger]
public async static void ManualTrigger(TextWriter log, int value)
{
using (var client = new HttpClient())
{
var rootUrl = ConfigurationManager.AppSettings.Get("WebJobTargetUrl");
client.BaseAddress = new System.Uri(rootUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Console.WriteLine("Call service");
var response = await client.PostAsJsonAsync("api/Reminder/ProcessDueReminders", new { ItemID = 1 });
Console.WriteLine("After service");
var result = await response.Content.ReadAsAsync<Result>();
Console.WriteLine("After result");
if (result.Success)
Console.WriteLine("Reminders Processed");
else
Console.WriteLine("Reminder process error: " + result.Error);
}
}
}
and the execution logs from the portal are:
I believe it has something to do with the asynchronous operation but I can't figure out a pattern that will work. Any help would be appreciated.
You must define the return value of your own async method as Task instead of void.
On a related note, you should suffix the name of your method with Async. That's not going to solve the problem, but it indicates that you're using the async/await pattern.
There is probably an exception in your PostAsJsonAsync call. Try to put a try catch around it to and log the error:
try {
var response = await client.PostAsJsonAsync("api/Reminder/ProcessDueReminders", new { ItemID = 1 });
} catch (Exception ex){
Console.WriteLine("Exception: "+ ex);
}
Console.WriteLine("After service");

UWP Cliet and Server

I have the UWP app("server") running on win10 prof, this UWP app is an application service and I have another UWP app(Client), which communicates with that service using TSP/IP. How many clients running on the other win10 devices can connect to the "server" at the same time?
Using the StreamSocketListener class, I believe you can handle an unlimited number of client socket connections (depending on implementation, hardware, bandwidth, etc.). Here's a basic example of the server-side implementation of the listener using a static class.
// Define static class here.
public static StreamSocketListener Listener { get; set; }
// This is the static method used to start listening for connections.
public static async Task<bool> StartServer()
{
Listener = new StreamSocketListener();
// Removes binding first in case it was already bound previously.
Listener.ConnectionReceived -= Listener_ConnectionReceived;
Listener.ConnectionReceived += Listener_ConnectionReceived;
try
{
await Listener.BindServiceNameAsync(VMS.Current.Port);
return true;
}
catch (Exception ex)
{
Listener.ConnectionReceived -= Listener_ConnectionReceived;
Listener.Dispose();
return false;
}
}
private static async void Listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
var remoteAddress = args.Socket.Information.RemoteAddress.ToString();
var reader = new DataReader(args.Socket.InputStream);
var writer = new DataWriter(args.Socket.OutputStream);
try
{
// Handle communication here. You'll likely use an infinite loop of reading from the input stream until the socket is disconnected.
}
catch (Exception ex)
{
writer.DetachStream();
reader.DetachStream();
return;
}
}
There are different ways of handling stream sockets once you have both ends connected, and I had to do some research and experimentation to find a process that worked for what I was doing.

Resources