I just created a chat App using signalR in C#(server) and JS(Client) and every thing is good and there is no problem when I run the server and client in my same device (localhost)
Now I want to run the client app out side my network , for example I want to make a chat with my friend who is living in another country using My app ,but I don't now how to do that and from where I need to start my search to do so.
Pleas if any one know how to do that or if any one know source that I can learn from it Help me
This is My signalR server Code
namespace PmmTcpListener
{
public class PmmSignalRServer : IDisposable
{
#region Private Properties
/// <summary>
/// To be set in <see cref="Dispose(bool)"/> method
/// </summary>
private bool _disposedValue;
public string SignalRwebAddress = "https://localhost:5050";
public bool IsStarted = false;
public bool cIsStarted = false;
public string cSignalRwebAddress = "https://localhost:5050/pmmchat";
private string PrevMessage = "";
private string CrntMessage = "";
private string ClientUrl = "";
#endregion
#region Constructor
/// <summary>
/// The main constructor for the class
/// Doing instantiation for Sql Commands based on database type <see cref="DbTypes"/>
/// By the way the default selected one is type <see cref="DbTypes.mysql"/>
/// </summary>
public PmmSignalRServer()
{
//Initialize the Sql Commands
//Sqlcmd = new MySqlCommand();
//AlarmsCommand = new MySqlCommand();
//SqlServerCmd = new SqlCommand();
//SqlServerAlarmsCommand = new SqlCommand();
//SqliteCmd = new SQLiteCommand();
//SqliteAlarmsCommand = new SQLiteCommand();
}
#endregion
#region MainFunctions
/// <summary>
/// To be set
/// </summary>
//public void Start(string SRport = "https://localhost:5050")
//{
// CreateWebHostBuilder().Build().Run();
//}
//private static IWebHostBuilder CreateWebHostBuilder() => WebHost.CreateDefaultBuilder().UseStartup<iStartup>().UseUrls("https://localhost:5050");
/// <summary>
/// To be set
/// </summary>
public void StartServe(string SRport = "http://localhost:5050")
{
SignalRwebAddress = SRport;
IsStarted = true;
Thread Serverthread = new Thread(StartSeerverThread);
Serverthread.Start();
}
/// <summary>
/// To be set
/// </summary>
private void StartSeerverThread()
{
try
{
WebHost.CreateDefaultBuilder()
.ConfigureServices(services => services.AddSignalR())
.ConfigureServices(services => services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
//builder.AllowAnyMethod().AllowAnyHeader()
// .WithOrigins("http://localhost:59054")
// .AllowCredentials();
builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
})))
.Configure(app => app.UseRouting().UseCors("CorsPolicy").UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/PmmChat");
})
)
.UseUrls(SignalRwebAddress)
.ConfigureLogging(config =>
{
config.ClearProviders();
})
.Build()
.Run();
}
catch (Exception ex)
{
PmmGlobFunctions.TrackThis(" StartServerThread : " + ex.Message);
}
}
/// <summary>
/// To be set
/// </summary>
public void StartClient(string hubUrl = "https://localhost:5050")
{
SignalRwebAddress = hubUrl;
cIsStarted = true;
//ClientUrl
ClientUrl = SignalRwebAddress.Replace(#"*", "localhost");
ClientUrl = ClientUrl + #"/pmmchat";
Thread thread = new Thread(StartClientThread);
thread.Start();
}
/// <summary>
/// To be set
/// </summary>
private void StartClientThread()
{
try
{
//IsStarted = true; .WithUrl(SignalRwebAddress+"/pmmchat")
var connection = new HubConnectionBuilder().WithUrl(ClientUrl).Build();
connection.StartAsync().Wait();
connection.InvokeCoreAsync("SendMessage", args: new[] { "PMM Users" }); // join the main group "PMM Users"
while (cIsStarted)
{
if (CrntMessage != PrevMessage)
{
connection.InvokeCoreAsync("SendMessage", args: new[] { "PmmServer", CrntMessage });
PrevMessage = CrntMessage;
}
}
connection.DisposeAsync();
}
catch (Exception ex)
{
PmmGlobFunctions.TrackThis(" StartClientThread : " + ex.Message);
}
}
/// <summary>
/// To be set
/// </summary>
public void StopClient()
{
cIsStarted = false;
}
/// <summary>
/// To be set
/// </summary>
public void SendFromServer(string message)
{
CrntMessage = message;
//connection.On("ReceiveMessage", (string userName, string message) =>
//{
// Console.WriteLine(userName + " : " + message);
//});
}
#endregion
#region Implement Dispose
/// <summary>
/// if <paramref name="disposing"/> = true, The dispose method has been called
/// by our code. Managed and unmanaged objects can be disposed
/// if <paramref name="disposing"/> = false, The dispose method has been called
/// by runtime finalizer. Unmanaged objects only should be disposed.
/// </summary>
/// <param name="disposing">disposing value</param>
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
// Dispose any managed objects
// ...
}
// Now disposed of any unmanaged objects
// ...
_disposedValue = true;
}
}
/// <summary>
/// Dispose method which implemented by <see cref="IDisposable"/>
/// </summary>
public void Dispose()
{
// Calling override Dispose method to be used in implemented method
Dispose(true);
// Commented by Dr.Mahmoud
//GC.SuppressFinalize(this);
}
#endregion
}
public class ConnectionMapping<T>
{
private readonly Dictionary<T, HashSet<string>> _connections =
new Dictionary<T, HashSet<string>>();
public int Count
{
get
{
return _connections.Count;
}
}
public void Add(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
connections = new HashSet<string>();
_connections.Add(key, connections);
}
lock (connections)
{
connections.Add(connectionId);
}
}
}
public IEnumerable<string> GetConnections(T key)
{
HashSet<string> connections;
if (_connections.TryGetValue(key, out connections))
{
return connections;
}
return Enumerable.Empty<string>();
}
public void Remove(T key, string connectionId)
{
lock (_connections)
{
HashSet<string> connections;
if (!_connections.TryGetValue(key, out connections))
{
return;
}
lock (connections)
{
connections.Remove(connectionId);
if (connections.Count == 0)
{
_connections.Remove(key);
}
}
}
}
}
public class ChatHub : Hub
{
// My Work --> Mohannad
private readonly static ConnectionMapping<string> _connections = new ConnectionMapping<string>();
public override Task OnConnectedAsync()
{
Groups.AddToGroupAsync(Context.ConnectionId, Context.User.Identity.Name);
return base.OnConnectedAsync();
}
public async Task SendMessageToClient(string user, string receiverConnectionId, string message)
{
foreach (var connectionId in _connections.GetConnections(user))
{
await Clients.Client(connectionId).SendAsync("ReceiveMessage", user, message);
}
// await Clients.Client(receiverConnectionId).SendAsync("ReceiveMessage", user, message);
}
public async Task SendMessageUsers(string user, string[] receiverUsersIds, string message)
{
// here you need to set the list of Users
await Clients.Users(receiverUsersIds).SendAsync("ReceiveMessage", user, message);
}
public async Task SendMessageOthers(string user, string message)
{
await Clients.Others.SendAsync("ReceiveMessage", user, message);
}
public async Task SendMessageToUser(string user, string receiverConnectionId, string message)
{
await Clients.Client(receiverConnectionId).SendAsync("ReceiveMessage", user, message);
}
public string GetConnectionId() => Context.ConnectionId;
//public override Task OnConnectedAsync()
//{
// string name = Context.User.Identity.Name;
// _connections.Add(name, Context.ConnectionId);
// return base.OnConnectedAsync();
//}
//public override Task OnDisconnectedAsync(Exception exception)
//{
// string name = Context.User.Identity.Name;
// _connections.Remove(name, Context.ConnectionId);
// return base.OnDisconnectedAsync(exception);
//}
// end Mohannad
public async Task SendMessage(string user, string message)
{
// await Clients.All.SendAsync("ReceiveMessage", user, PmmCommandReader.ReadCommand(message));
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("PMM Users").SendAsync("ReceiveMessage", user, message);
}
public Task JoinGroup(string groupName)
{
return Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
}
//End of NameSpace
}
Related
I am using Service Bus Topic trigger azure function, and this function is basically performing below tasks:
Calling external API(Janrain).
After that it is again calling external API(Mailjet) to trigger email.
Then it is publishing message into Service Bus Topic.
In the Azure Application insights I can see there are lot of System.Net.Sockets.SocketException logged.
Exception details:
ExceptionMessage:The SSL connection could not be established, see
inner exception., StackTrace: at
System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream
stream, SslClientAuthenticationOptions sslOptions, CancellationToken
cancellationToken) at
System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage
request, Boolean allowHttp2, CancellationToken cancellationToken)
at
System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage
request, CancellationToken cancellationToken) at
System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage
request, CancellationToken cancellationToken) at
System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage
request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage
request, CancellationToken cancellationToken) at
System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage
request, CancellationToken cancellationToken) at
System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask,
HttpRequestMessage request, CancellationTokenSource cts, Boolean
disposeCts) at
Mailjet.Client.MailjetClient.PostAsync(MailjetRequest request)
Could you please suggest how can I fix this issue?
Below is my Janrain API client:
public class JanrainApiClient : IJanrainApiClient
{
#region private fields
private readonly ILogger<JanrainApiClient> _logger;
private readonly IHttpClientFactory _httpClientFactory;
private readonly JanrainConfigOption _janrainConfigOption;
#endregion
#region ctors
public JanrainApiClient(ILogger<JanrainApiClient> logger,
IOptions<JanrainConfigOption> janrainConfigOption,
IHttpClientFactory httpClientFactory)
{
this._logger = logger;
this._janrainConfigOption = janrainConfigOption.Value;
this._httpClientFactory = httpClientFactory;
}
#endregion
#region public methods
public async Task<JanrainResultDto> FindAsync(string userUUID)
{
try
{
_logger.LogInformation("{class} -> {method} -> Start",
nameof(JanrainApiClient), nameof(JanrainApiClient.FindAsync));
JanrainResultDto resultDto = new JanrainResultDto();
var request = GetJanrainApiRequest(userUUID);
var httpClient = _httpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(GetServiceUrl(request));
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(_janrainConfigOption.Scheme, _janrainConfigOption.ApiAuth);
var response = await httpClient.GetAsync(GetServiceUrl(request));
var jsonAsString = await response.Content.ReadAsStringAsync();
JanrainApiResponse entityFindResponse = jsonAsString.AsPoco<JanrainApiResponse>();
if (entityFindResponse != null && entityFindResponse.Results != null)
{
resultDto = entityFindResponse.Results.FirstOrDefault();
}
else
{
_logger.LogError($"Error while requesting Janrain info for UserUUId:{userUUID}." +
$"Error:{entityFindResponse?.Error}, ErrorMessage:{entityFindResponse?.ErrorDescription}");
}
_logger.LogInformation("{class} -> {method} -> End",
nameof(JanrainApiClient), nameof(JanrainApiClient.FindAsync));
return resultDto;
}
catch (Exception ex)
{
_logger.LogError($"Exception while calling Janrain entity Find API for UserUUId :{userUUID}, " +
$"Error message:{ex.Message}, StackTrace:{ex.StackTrace}");
throw;
}
}
#endregion
#region private methods
private JanrainApiRequest GetJanrainApiRequest(string userUUId)
{
return new JanrainApiRequest
{
Username = string.Empty,
TypeName = _janrainConfigOption.TypeName,
Attributes = JanrainResultDto.Attributes(),
QueryFilter = $"uuid='{userUUId}'",
ClientId = _janrainConfigOption.ClientId,
};
}
private string GetServiceUrl(JanrainApiRequest request)
{
return $"{_janrainConfigOption.EntityFindApiUrl}{request.ToQueryString()}";
}
#endregion
}
Below is my Mailjet client factory:
public class MailjetClientFactory : IMailjetClientFactory
{
#region private fields
private readonly MailjetConfigOption _mailjetConfigOption;
#endregion
#region ctors
public MailjetClientFactory(IOptions<MailjetConfigOption> mailjetConfigOption)
{
_mailjetConfigOption = mailjetConfigOption.Value;
}
#endregion
#region public methods
/// <summary>
/// Create Mailjet client
/// </summary>
/// <returns>The IMailjetClient instance.</returns>
public IMailjetClient CreateClient()
{
return new MailjetClient(_mailjetConfigOption.PublicKey,
_mailjetConfigOption.SecretKey)
{
Version = ApiVersion.V3_1
};
}
#endregion
}
Sending email with Mailjet API:
public async Task<MailjetResponse> SendEmail(MailjetEmailMessage emailMessage)
{
var mailJetMessage = buildMailJetMessages.BuildMailjetMessageFor(emailMessage);
var mailJetClient = createMailJetClients.CreateClient();
var mailJetResponse = await mailJetClient.PostAsync(new MailjetRequest
{
Resource = Send.Resource,
}.Property(Send.Messages, mailJetMessage));
return mailJetResponse;
}
Service Bus Message Factory:
public class AzureServiceBusFactory : IMessageBusFactory
{
#region private fields
private readonly ServiceBusConfigOption _serviceBusConfigOption;
private readonly object _lockObject = new object();
private readonly ConcurrentDictionary<string, ServiceBusClient> _clients = new ConcurrentDictionary<string, ServiceBusClient>();
private readonly ConcurrentDictionary<string, ServiceBusSender> _senders = new ConcurrentDictionary<string, ServiceBusSender>();
#endregion
public AzureServiceBusFactory(IOptions<ServiceBusConfigOption> serviceBusConfigOption)
{
_serviceBusConfigOption = serviceBusConfigOption.Value;
}
#region public methods
/// <summary>
/// Get ServiceBusClient
/// </summary>
/// <param name="senderName"></param>
/// <returns></returns>
public IMessageBus GetClient(string senderName)
{
var connectionString = _serviceBusConfigOption.ConnectionString;
var key = $"{connectionString}-{senderName}";
if (this._senders.ContainsKey(key) && !this._senders[key].IsClosed)
{
return AzureServiceBus.Create(this._senders[key]);
}
var client = this.GetServiceBusClient(connectionString);
lock (this._lockObject)
{
if (this._senders.ContainsKey(key) && this._senders[key].IsClosed)
{
if (this._senders[key].IsClosed)
{
this._senders[key].DisposeAsync().GetAwaiter().GetResult();
}
return AzureServiceBus.Create(this._senders[key]);
}
var sender = client.CreateSender(senderName);
this._senders[key] = sender;
}
return AzureServiceBus.Create(this._senders[key]);
}
#endregion
#region protected methods
/// <summary>
/// Create ServiceBusClient
/// </summary>
/// <param name="connectionString"></param>
/// <returns></returns>
protected virtual ServiceBusClient GetServiceBusClient(string connectionString)
{
var key = $"{connectionString}";
lock (this._lockObject)
{
if (this.ClientDoesnotExistOrIsClosed(connectionString))
{
var client = new ServiceBusClient(connectionString, new ServiceBusClientOptions
{
TransportType = ServiceBusTransportType.AmqpTcp
});
this._clients[key] = client;
}
return this._clients[key];
}
}
#endregion
#region private methods
/// <summary>
/// Check ClientDoesnotExistOrIsClosed
/// </summary>
/// <param name="connectionString"></param>
/// <returns></returns>
private bool ClientDoesnotExistOrIsClosed(string connectionString)
{
return !this._clients.ContainsKey(connectionString) || this._clients[connectionString].IsClosed;
}
#endregion
}
internal class AzureServiceBus : IMessageBus
{
#region private fields
private const string ContentType = "application/json";
private readonly ServiceBusSender _serviceBusSender;
#endregion
#region ctors
internal AzureServiceBus(ServiceBusSender serviceBusSender)
{
this._serviceBusSender = serviceBusSender;
}
#endregion
#region public methods
/// <summary>
/// Publish message into Service Bus Topic
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <returns></returns>
public async Task PublishMessageAsync<T>(T message, string messageId)
{
var serviceBusMessage = new ServiceBusMessage(Encoding.UTF8.GetBytes(message.AsJson()))
{
ContentType = ContentType
};
serviceBusMessage.MessageId = messageId;
await this._serviceBusSender.SendMessageAsync(serviceBusMessage);
}
/// <summary>
/// Publish message into Service Bus Topic
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="message"></param>
/// <param name="messageId"></param>
/// <param name="filterPropertyName"></param>
/// <param name="filterPropertyValue"></param>
/// <returns></returns>
public async Task PublishMessageAsync<T>(T message, string messageId, string filterPropertyName, string filterPropertyValue)
{
var serviceBusMessage = new ServiceBusMessage(Encoding.UTF8.GetBytes(message.AsJson()))
{
ContentType = ContentType
};
serviceBusMessage.MessageId = messageId;
serviceBusMessage.ApplicationProperties.Add(filterPropertyName, filterPropertyValue);
serviceBusMessage.CorrelationId = filterPropertyValue;
await this._serviceBusSender.SendMessageAsync(serviceBusMessage);
}
#endregion
#region internal methods
internal static IMessageBus Create(ServiceBusSender sender)
{
return new AzureServiceBus(sender);
}
#endregion
}
DI registrations:
builder.Services.AddSingleton<IJanrainApiClient, JanrainApiClient>();
builder.Services.AddSingleton<IMailjetClientFactory, MailjetClientFactory>();
builder.Services.AddSingleton<IMessageBusFactory, AzureServiceBusFactory>();
builder.Services.AddTransient<IMailjetEmailService, MailjetEmailService>();
I have the following code for a MQTT Subscriber in a Background Task:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using PickByLight.BackgroundTask.Models;
using PickByLight.Database.Wrapper.Interfaces;
using PickByLight.Logic;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
namespace PickByLight.BackgroundTask
{
/// <summary>
/// Hosted MQTT Background Service
/// </summary>
public class HostedMQTTService : IHostedService, IDisposable
{
private readonly Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();
/// <summary>
/// MQTT Client
/// </summary>
private MqttClient MqttClient { get; set; }
/// <summary>
/// Name of the Pick by Light
/// </summary>
private string PickByLight_Name { get; set; }
/// <summary>
/// MQTT is activated
/// </summary>
private bool MqttIsActive { get; set; }
/// <summary>
/// IP Adress of the MQTT URL
/// </summary>
private string MqttURL { get; set; }
/// <summary>
/// Storage Process for an material
/// </summary>
private MaterialStorageProcess StorageProcess { get; set; }
/// <summary>
/// Service Scope Factory
/// </summary>
private IServiceScopeFactory ServiceScopeFactory { get; set; }
/// <summary>
/// Configuration
/// </summary>
private IConfiguration Configuration { get; set; }
/// <summary>
/// Logger
/// </summary>
private readonly ILogger<HostedMQTTService> _logger;
/// <summary>
/// Constructor
/// </summary>
/// <param name="configuration"></param>
public HostedMQTTService(IConfiguration configuration, ILogger<HostedMQTTService> logger, IServiceScopeFactory serviceScopeFactory)
{
this.PickByLight_Name = configuration.GetValue<string>("PickByLight_Name");
this.MqttURL = configuration.GetValue<string>("MQTTUrl");
this.MqttIsActive = configuration.GetValue<bool>("MQTTConnection");
this.ServiceScopeFactory = serviceScopeFactory;
this.Configuration = configuration;
this._logger = logger;
}
/// <summary>
/// Start the Task of the Background Service
/// </summary>
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Background-Service started...");
while (true)
{
try
{
//No Object is created
if (this.MqttClient == null)
{
_logger.LogInformation("Try to establishe new MQTT Client");
this.MqttClient = CreateNewMqttConnection();
}
else if (this.MqttClient.IsConnected == false)
{
_logger.LogInformation("MQTT Client is disconnected... Try to reconnect!");
this.MqttClient = CreateNewMqttConnection();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ein schwerwiegender Fehler im MQTT Background-Service ist aufgetreten.");
}
}
}
/// <summary>
/// Prints out all received messages
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Mqtt_Message_Received(object sender, MqttMsgPublishEventArgs e)
{
try
{
var agcMessage = Encoding.UTF8.GetString(e.Message);
_logger.LogInformation("Topic: " + e.Topic + " | Nachricht: " + agcMessage + " | QOS: " + e.QosLevel);
var resultString = Encoding.UTF8.GetString(e.Message);
MqttReadTopicClass mqttContent = JsonConvert.DeserializeObject<MqttReadTopicClass>(resultString);
using (var scope = this.ServiceScopeFactory.CreateScope())
{
var storageConfigurationManager = scope.ServiceProvider.GetService<IStorageConfigurationManager>();
var storageElementManager = scope.ServiceProvider.GetService<IStorageElementManager>();
this.StorageProcess = new MaterialStorageProcess(storageConfigurationManager, storageElementManager, this.Configuration);
StorageProcess.Remove(mqttContent.storageLocation);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Schwerwiegender Fehler beim Lesen von MQTT Nachrichten");
}
}
/// <summary>
/// Create new MQTT connection if connection is lost or doesn't exist
/// </summary>
private MqttClient CreateNewMqttConnection()
{
_logger.LogInformation("Create MQTT Client");
MqttClient client = new MqttClient(this.MqttURL, 32005, false, null, null, MqttSslProtocols.None);
string clientId = Guid.NewGuid().ToString();
client.MqttMsgPublishReceived += Mqtt_Message_Received;
client.Connect(clientId);
client.Subscribe(new string[] { "buttonpress_sepioo_pdi/" + this.PickByLight_Name }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
_logger.LogInformation("MQTT Client created");
return client;
}
/// <summary>
/// Stop the Task of the Background Service
/// </summary>
public async Task StopAsync(CancellationToken cancellationToken)
{
//Stop called without start
if (_executingTask == null)
{
return;
}
try
{
//Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
//wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
}
/// <summary>
/// Dispose the Background Service
/// </summary>
public void Dispose()
{
_stoppingCts.Cancel();
}
}
}
In my startup.cs File i am doing the following:
//Register Background Task
services.AddHostedService<HostedMQTTService>();
The problem is, that it seems to me that the hosted service is blocking the user-interface/webserver threads because i can not access the url of the .net 6 mvc application.
Could you give me a hint or a solution to this problem?
Thanks.
You will need to change your StartAsync-method to something like this:
public Task StartAsync(CancellationToken cancellationToken)
{
return Task.Run(() =>
{
_logger.LogInformation("Background-Service started...");
while (!cancellationToken.IsCancellationRequested)
{
try
{
//No Object is created
if (this.MqttClient == null)
{
_logger.LogInformation("Try to establish new MQTT Client");
this.MqttClient = CreateNewMqttConnection();
}
else if (this.MqttClient.IsConnected == false)
{
_logger.LogInformation("MQTT Client is disconnected... Try to reconnect!");
this.MqttClient = CreateNewMqttConnection();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Ein schwerwiegender Fehler im MQTT Background-Service ist aufgetreten.");
}
}
});
}
You are blocking the process, because your hosted service never starts.
Remove the while(true) loop from the Start method.
Ensure base.StartAsync(cancellationToken); is always called.
Edit: I saw you implement the IHostedService interface. Try to inherits from the BackgroundService class
I try to use map functionality in my app using Xamarin.Forms.
In this part of the code I get the permission for allow to see my location in the map.
[Obsolete]
private async void GetPermession()
{
try
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse);
//var status = await CrossPermissions.Current.CheckPermissionStatusAsync<LocationWhenInUsePermission>();
if (status != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse))
{
await
DisplayAlert("Need your location", "We need to acces your location", "Ok");
}
var result = await CrossPermissions.Current.RequestPermissionsAsync(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse);
if (result.ContainsKey(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse))
status = result[Plugin.Permissions.Abstractions.Permission.LocationWhenInUse];
}
if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
this.LocationMap.IsShowingUser = true;
else
await
DisplayAlert("Need your location", "We need to acces your location", "Ok");
}
catch (Exception exception)
{
await
DisplayAlert("Error", exception.Message, "Ok");
}
}
Visual Studio tell me that
CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse)) is obsolete, and the new method is:
CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync()
But, if I use the new method
var result = await CrossPermissions.Current.RequestPermissionsAsync(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse);
if (result.ContainsKey(Plugin.Permissions.Abstractions.Permission.LocationWhenInUse))
status = result[Plugin.Permissions.Abstractions.Permission.LocationWhenInUse];
the result doesn't have a .ContainsKey method.
How can I solve this?
Sorry for my bad English, and thanks
You can grab the permission using Xamarin.Essential and Dependency service like this:
Interface
public interface IPermissionHelper
{
Task<PermissionStatus> RequestPermissionsAsync();
}
Call it from Shared project:
await DependencyService.Get<IPermissionHelper>().RequestPermissionsAsync();
iOS Renderer:
public class PermissionHelper : IPermissionHelper
{
public PermissionHelper()
{
}
/// <summary>
/// Defines the showTrackingMap.
/// </summary>
LocationCheck showTrackingMap;
/// <summary>
/// The RequestPermissionsAsync.
/// </summary>
/// /// <returns>The <see cref="Task<PermissionStatus>"/>.</returns>
public async Task<PermissionStatus> RequestPermissionsAsync()
{
PermissionStatus permission = PermissionStatus.Unknown;
showTrackingMap = new LocationCheck((s, ev) => {
if ((ev as LocationCheck.LocationCheckEventArgs).Allowed)
{
permission = PermissionStatus.Granted;
}
else
{
permission = PermissionStatus.Denied;
}
showTrackingMap.Dispose();
});
while (permission == PermissionStatus.Unknown)
{
await Task.Delay(10);
}
return permission;
}
}
public class LocationCheck : NSObject, ICLLocationManagerDelegate
{
public class LocationCheckEventArgs : EventArgs
{
public readonly bool Allowed;
public LocationCheckEventArgs(bool Allowed)
{
this.Allowed = Allowed;
}
}
CLLocationManager locationManager;
EventHandler locationStatus;
public LocationCheck(EventHandler locationStatus)
{
this.locationStatus = locationStatus;
Initialize();
}
public LocationCheck(NSObjectFlag x) : base(x) { Initialize(); }
public LocationCheck(IntPtr handle) : base(handle) { Initialize(); }
public LocationCheck(IntPtr handle, bool alloced) : base(handle, alloced) { Initialize(); }
public void Initialize()
{
locationManager = new CLLocationManager
{
Delegate = this
};
locationManager.RequestWhenInUseAuthorization();
}
[Export("locationManager:didChangeAuthorizationStatus:")]
public void AuthorizationChanged(CLLocationManager manager, CLAuthorizationStatus status)
{
switch (status)
{
case CLAuthorizationStatus.AuthorizedAlways:
case CLAuthorizationStatus.AuthorizedWhenInUse:
locationStatus.Invoke(locationManager, new LocationCheckEventArgs(true));
break;
case CLAuthorizationStatus.Denied:
case CLAuthorizationStatus.Restricted:
locationStatus.Invoke(locationManager, new LocationCheckEventArgs(false));
break;
}
}
protected override void Dispose(bool disposing)
{
locationStatus = null;
locationManager.Delegate = null;
locationManager.Dispose();
base.Dispose(disposing);
}
}
public async void GetPermission()
{
var permission = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
if (permission != PermissionStatus.Granted)
{
permission = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
}
else if(permission == PermissionStatus.Granted)
this.LocationMap.IsShowingUser = true;
if (permission != PermissionStatus.Granted)
return;
}
I resolve, using this method, thaks to all to answering
I'm building a Tic-Tac_toe api game. The game work ok, until one of the players press on a square that finish the game(either he wins or fill the board).
When I enabled all CLR exceptions for the last move, this is the exception I saw for line var user = await UserManager.FindByIdAsync(userId);
"Additional information: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe."
Importent to know when a player click a square, it is a 'POST' method.
Here's my code:
public class GamesApiController : ApiController
{
ApplicationDbContext context = new ApplicationDbContext();
private ApplicationUserManager _userManager;
public IEnumerable<ApplicationUser> Get()
{
return context.Users;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? System.Web.HttpContext.Current.Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
#region Methods
/// <summary>
/// update the server data by reciving the model and square and returns the new model
/// </summary>
/// <param name="_model"></param>
/// <param name="squareId"></param>
/// <returns></returns>
//square clicked via post
[Route("api/gamesapi/{squareId}")]
public async Task<HttpResponseMessage> Post([FromBody]GameModel model, int squareId)
{
HttpResponseMessage response;
if (model == null)
{
//Utilites.CreateMsgCookie(Response, "Error", "Sorry, an unknown error has occurred");
response = Request.CreateErrorResponse(HttpStatusCode.NotFound, "model wasn't found");
return response;
}
//GameModel model = JsonConvert.DeserializeObject<GameModel>(_model);
Game game = GetGameById(model.Game.GameId);
if (game == null)
{
response = Request.CreateErrorResponse(HttpStatusCode.NotFound, "game wasn't found");
}
else
{
if (game.UserIdTurn == game.User1Id) //pressing user is user1
{
ChangeSquareState(game, squareId, true);
game.UserIdTurn = game.User2Id;
}
else //game.UserIdTurn == game.User2Id - pressing user is user2
{
ChangeSquareState(game, squareId, false);
game.UserIdTurn = game.User1Id;
}
SquareState[] board = new SquareState[] {game.Square1,game.Square2,game.Square3,game.Square4,
game.Square5,game.Square6,game.Square7,game.Square8,game.Square9};
if (didPlayerWin(board))
{
game.WinnerId = model.User.Id;
await UpdateUserGameState(1, game.User1Id);
await UpdateUserGameState(2, game.User2Id);
game.IsGameOver = true;
}
else
{
bool isBoardFull = true;
for (int i = 0; i < board.Length; i++)
{
if (board[i] == SquareState.Blank)
{
isBoardFull = false;
break;
}
}
if (isBoardFull)
{
await UpdateUserGameState(3, game.User1Id);
await UpdateUserGameState(3, game.User2Id);
game.IsGameOver = true;
}
}
context.SaveChanges();
response = Request.CreateResponse(HttpStatusCode.OK, game);
}
return response;
}
/// <summary>
/// When a game is over, recive a gameState and update the user. 1 for a win, 2 for loss, 3 for aa draw
/// </summary>
/// <param name="gameState"></param>
private async Task UpdateUserGameState(int gameState, string userId)
{
var user = await UserManager.FindByIdAsync(userId);
switch (gameState)
{
case 1:
user.GamesWon++;
break;
case 2:
user.GamesLost++;
break;
case 3:
user.GamesDraw++;
break;
default:
break;
}
UserManager.UpdateAsync(user);
}
[HttpGet]
[Route("api/gamesapi/{gameId}")]
/// <summary>
/// method to bring the latest game's state from the context and send it back in a GameModel
/// </summary>
/// <param name="_model"></param>
/// <returns></returns>
public HttpResponseMessage Get(int gameId)
{
HttpResponseMessage response;
Game game = GetGameById(gameId);
if (game == null)
{
response = Request.CreateErrorResponse(HttpStatusCode.NotFound, "game wasn't found");
}
else
{
response = Request.CreateResponse(HttpStatusCode.OK, game);
}
return response;
}
/// <summary>
/// method that check if the board have a line(3 squars in a row)
/// of the same element of user1 or user2 , defult - returns fault
/// </summary>
/// <param name="board"></param>
/// <returns></returns>
private bool didPlayerWin(SquareState[] board)
{
}
/// <summary>
/// change the SquareState of a specific square of the sent game according to the pressing user
/// </summary>
/// <param name="game"></param>
/// <param name="SquareId"></param>
/// <param name="_isUser1"></param>
private void ChangeSquareState(Game game, int SquareId, bool _isUser1)
{
}
/// <summary>
/// get game from context by gameId , Defult result - null
/// </summary>
/// <param name="gameId"></param>
/// <returns></returns>
private Game GetGameById(int gameId)
{
}
#endregion
}
I think you missed to wait for UpdateUserAsync() in method UpdateUserGameState():
private async Task UpdateUserGameState(int gameState, string userId)
{
var user = await UserManager.FindByIdAsync(userId);
// ...
// add missing await
await UserManager.UpdateAsync(user);
}
I am trying to implement a custom membership provider in an asp.net mvc 4 web application using ninject for dependency injection. Here is the code I have until now.
public interface IAccountRepository
{
void Initialize(string name, NameValueCollection config);
string ApplicationName { get; set; }
bool ChangePassword(string username, string oldPassword, string newPassword);
bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
string newPasswordAnswer);
MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
bool DeleteUser(string username, bool deleteAllRelatedData);
bool EnablePasswordReset { get; }
bool EnablePasswordRetrieval { get; }
MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
out int totalRecords);
/* I have deleted here all other methods and properties of membership for brevity */
}
.
public class AccountRepository : IAccountRepository
{
private string applicationName;
private bool enablePasswordReset;
private bool enablePasswordRetrieval;
private int maxInvalidPasswordAttempts;
private int minRequiredNonAlphanumericCharacters;
private int passwordAttemptWindow;
private MembershipPasswordFormat passwordFormat;
private string passwordStrengthRegularExpression;
private bool requiresQuestionAndAnswer;
private bool requiresUniqueEmail;
private int minRequiredPasswordLength;
public void Initialize(string name, NameValueCollection config)
{
applicationName = GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
maxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
passwordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
minRequiredNonAlphanumericCharacters = Convert.ToInt32(GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
minRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "6"));
enablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
passwordStrengthRegularExpression = Convert.ToString(GetConfigValue(config["passwordStrengthRegularExpression"], ""));
}
public string ApplicationName
{
get { return applicationName; }
set { applicationName = value; }
}
public bool ChangePassword(string username, string oldPassword, string newPassword)
{
throw new NotImplementedException();
}
public bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion,
string newPasswordAnswer)
{
throw new NotImplementedException();
}
public MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
throw new NotImplementedException();
}
public bool DeleteUser(string username, bool deleteAllRelatedData)
{
using (var database = new KinematDbContext())
{
// Query to get the user with the specified username
User user = database.Users.SingleOrDefault(u => u.Username == username);
if (user != null)
{
if (deleteAllRelatedData)
{
database.Users.Remove(user);
}
else
{
user.IsDeleted = true;
}
database.SaveChanges();
return true;
}
return false;
}
}
public bool EnablePasswordReset
{
get { return enablePasswordReset; }
}
public bool EnablePasswordRetrieval
{
get { return enablePasswordRetrieval; }
}
public MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize,
out int totalRecords)
{
throw new NotImplementedException();
}
public MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize,
out int totalRecords)
{
throw new NotImplementedException();
}
/* I have deleted here all other methods and properties of membership for brevity */
}
.
public class AccountMembershipProvider : MembershipProvider
{
[Inject]
public IAccountRepository AccountRepository { get; set; }
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
AccountRepository.Initialize(name, config);
/* Here comes the error: Object reference not set to an instance of an object. */
}
public override string ApplicationName
{
get { return AccountRepository.ApplicationName; }
set { AccountRepository.ApplicationName = value; }
}
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
return AccountRepository.ChangePassword(username, oldPassword, newPassword);
}
}
and this is my ninject controller factory(I also have set the controller factory in Application_Start())
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
ninjectKernel.Bind<IAccountRepository>().To<AccountRepository>();
ninjectKernel.Bind<IRoleRepository>().To<RoleRepository>();
ninjectKernel.Inject(Membership.Provider);
ninjectKernel.Inject(Roles.Provider);
}
}
as I mention in a comment in the AccountMembershipProvider class when the AccountRepository.Initialize(name, config); is called I receive the following error: Object reference not set to an instance of an object. After debugging the application and read articles about how ninject works I cannot figure out what the problem is about. Please, can you give any explanation? Thank you.
I've run into a similar problem using a Custom Membership Provider. If you want to call the initialize method in the AccountRepository you could do the following:
Configure your DI with ninject in App_Start using the following (available via nuget):
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(() => CreateKernel());
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
DependencyResolver.SetResolver(new NinjectServiceLocator(kernel));
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
//add your bindings here
kernel.Bind<IAccountRepository>().To<AccountRepository>();
kernel.Bind<MembershipProvider>().To<AccountMembershipProvider>().InRequestScope();
kernel.Bind<RoleProvider>().To<AccountRoleProvider>().InRequestScope(); //In case you have a custom Role Provider.
}
}
Then in your custom provider:
public class AccountMembershipProvider : MembershipProvider
{
private readonly IAccountRepository _repository;
public AccountMembershipProvider()
{
_repository = ServiceLocator.Current.GetInstance<IAccountRepository>();
_repository.Initialize();
}
public override bool ValidateUser(string username, string password)
{
return _repository.IsValidLogin(username, password);
}
...//Other methods
}
Hope this helps,
Try to do the initialization for registering instances in Global.asax.
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// TODO register your binding here
...
}
}
Not the answer you're looking for, but I tried to do this myself a while ago and while I did manage to find a way to make it work, I found the solution to be too complex and brittle for production use.
I simply gave up on the idea of using Injection with my custom provider, because of the way Membership creates the provider. It's just not worth the headaches in my opinion.
I also think using Injection breaks the whole concept of the Membership provider, since the idea is that providers are supposed to be pluggable, and you can replace one with another without making any changes to your code. That's simply not possible to do if you have to have configuration code in your app to configure the database context..
Ok, you might argue that you won't be changing the provider.. in which case, Why bother with the provider at all then? Why not just implement a custom IIdentity and IPrincipal implementations.
How about adding the following line into your AddBindings() method
kernel.Bind<AccountMembershipProvider>().ToMethod(ctx => Membership.Provider);
I used ninject and custom membership provider with mvc3
Not sure if it helps you but you can compare yours with mine.
[assembly: WebActivator.PreApplicationStartMethod(typeof(VBooks.Web.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(VBooks.Web.App_Start.NinjectWebCommon), "Stop")]
namespace VBooks.Web.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
public class ProviderInitializationHttpModule : IHttpModule
{
public ProviderInitializationHttpModule(MembershipProvider membershipProvider) { }
public void Init(HttpApplication context) { }
void IHttpModule.Dispose()
{
}
}
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
//
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IRegisterService>().To<RegisterService>();
kernel.Bind<IEmailService>().To<EmailService>();
kernel.Bind<IAccountService>().To<AccountService>();
kernel.Bind<ICoverService>().To<CoverService>();
kernel.Bind<IAdminLogService>().To<AdminLogService>();
kernel.Bind<MembershipProvider>().ToMethod(ctx => Membership.Provider);
kernel.Bind<IHttpModule>().To<ProviderInitializationHttpModule>();
// Add data and infrastructure modules
var modules = new List<INinjectModule>
{
new RepositoryModule()
};
kernel.Load(modules);
}
}
}
Instead of implementing DefaultControllerFactory you can implement IDependencyResolver:
public class NinjectDependencyResolver : IDependencyResolver
{
readonly IKernel _kernel;
public NinjectDependencyResolver()
{
_kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return _kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _kernel.GetAll(serviceType);
}
void AddBindings()
{
// Remember to add bindings here.
_kernel.Bind<IAccountRepository>().To<EFAccountRepository>();
}
}
Then in global.asax.cs instead of setting ControllerFactory you can set DependencyResolver:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
DependencyResolver.SetResolver(new NinjectDependencyResolver()); // Here.
}
}
Then in your implementation of MembershipProvider ask current DependencyResolver(Ninject) to create you an instance of, in this case, IAccountRepository:
public class CustomMembershipProvider : MembershipProvider
{
private readonly IAccountRepository _repository;
public OpenTibiaMembershipProvider()
{
_repository = (IAccountRepository)DependencyResolver.Current.GetService(typeof(IAccountRepository));
}
// Rest of implementation.
}
Hope this helps.