Ok thanks... I try it
How can I call AppService from the beginning? How can I do it from the Web.Host?
Startup
services.AddSignalR(_appConfiguration);
Static Class
public static class SignalRExtension
{
private const string WEBAPI = "!GSSYSTEM_WAPI";
private static SignalRExtensionAppService _signalRExtensionAppService;
private static IRepository<Machine> _machineRepository;
public static void AddSignalR(this IServiceCollection services, IConfiguration configuration)
{
var url = configuration["SignalR:Url"];
//_signalRExtensionAppService = signalRExtensionAppService;
//_machineRepository = machineRepository;
HubConnection connection = null;
connection = new HubConnectionBuilder()
.WithUrl(url)
.Build();
connection.On<string, string, string, int>("GetMessage", (from, to, message, type) =>
{
Task.Run(async () =>
{
var newMessage = $"{"SIG"}: {message}";
//log.Info(newMessage);
//Console.WriteLine(newMessage);
Recieve_SendMessageToUser(from, to, message, type);
});
});
connection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await connection.StartAsync();
connection.InvokeAsync<string>("JoinGroup", "monitor", WEBAPI, "1");
};
connection.StartAsync();
connection.InvokeAsync<string>("JoinGroup", "monitor", WEBAPI, "1");
services.AddSingleton(connection);
}
public static void Recieve_SendMessageToUser(string from, string to, string message, int type)
{
string action = message.Split('@')[0];
switch (action)
{
case "ActualizeRegisterDB":
ActualizeRegisterDB(message.Split('@')[1], message.Split('@')[2], message);
break;
default:
break;
}
}
private static async Task ActualizeRegisterDB(string machineName, string tenant, string message)
{
int tenantId = 0;
try
{
var lastLogin = DateTime.ParseExact(message.Split('@')[3], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
var lastLogout = DateTime.ParseExact(message.Split('@')[4], "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
int.TryParse(message.Split('@')[2], out tenantId);
CreateMachineDto createMachine = new CreateMachineDto()
{
Name = message.Split('@')[1],
LastLogin = lastLogin,
LastLogout = lastLogout,
TenantId = tenantId
};
//Call to SignalRExtensionAppService
}
catch (Exception ex)
{
throw;
}
}
}
AppService
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public class MachineAppService : AsyncCrudAppService<Machine, MachineDto, int, ControllerInputDto, CreateMachineDto, UpdateMachineDto>, IMachineAppService
{
#region "Members"
public ILogger log { get; set; }
private readonly IRepository<Application> _applicationRepository;
private readonly IRepository<Machine> _machineRepository;
private readonly IRepository<AppVersion> _appVersionRepository;
private readonly IRepository<Tag> _tagRepository;
private readonly IRepository<License> _licenseRepository;
private readonly IRepository<Tenant> _tenantRepository;
private readonly IRepository<AppVendor> _appVendorRepository;
private readonly IRepository<Active> _activeRepository;
private readonly IRepository<SamAudit> _samAuditRepository;
private readonly IRepository<ProductGroup> _productGroupRepository;
private readonly IObjectMapper _objectMapper;
private readonly HubConnection _connection;
private readonly IFileProvider _fileProvider;
#endregion
#region "Constructor"
public MachineAppService(
IRepository<Machine> machineRepository,
IRepository<Application> applicationRepository,
IRepository<AppVersion> appVersionRepository,
IRepository<Tag> tagRepository,
IRepository<License> licenseRepository,
IRepository<Tenant> tenantRepository,
IRepository<AppVendor> appVendorRepository,
IRepository<Active> activeRepository,
IRepository<SamAudit> samAuditRepository,
IRepository<ProductGroup> productGroupRepository,
IObjectMapper objectMapper,
HubConnection connection,
IFileProvider fileProvider
) : base(machineRepository)
{
_applicationRepository = applicationRepository;
_machineRepository = machineRepository;
_appVersionRepository = appVersionRepository;
_tagRepository = tagRepository;
_licenseRepository = licenseRepository;
_tenantRepository = tenantRepository;
_appVendorRepository = appVendorRepository;
_activeRepository = activeRepository;
_samAuditRepository = samAuditRepository;
_productGroupRepository = productGroupRepository;
_objectMapper = objectMapper;
_connection = connection;
_fileProvider = fileProvider;
log = NullLogger.Instance;
}
#endregion
#region "Calls to SignalR"
public async Task UpdateSigToMachine(List<UpdateMachineDto> input)
{
// signal => SIG_SHUTDOWN / SIG_STARTUP
var tenantId = AbpSession.TenantId;
try
{
var machines = (from a in input
select a);
foreach (var item in machines)
{
var signal = item.Active == true ? "SIG_STARTUP" : "SIG_SHUTDOWN";
await Update(item);
await _connection.InvokeAsync("SendSIGToMachine", item.Name, signal, tenantId.ToString());
}
return;
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
return;
}
}
public async Task UpdateSigToAll(string signal)
{
var tenantId = AbpSession.TenantId;
//int tenantId = 0;
//int.TryParse(TenantId, out tenantId);
// signal => SIG_SHUTDOWN / SIG_STARTUP
bool recibeSignal = signal == "SIG_SHUTDOWN" ? false : true;
await _connection.InvokeAsync("SendSIGToEverybody", tenantId, signal);
try
{
//var allMachines = _machineRepository.GetAll()
// .Where(x => x.TenantId == tenantId);
var allMachines = _machineRepository.Query(a => a.Where(x => x.TenantId == tenantId));
foreach (var machine in allMachines)
{
if (recibeSignal)
machine.LastLogin = DateTime.Now;
else
machine.LastLogout = DateTime.Now;
machine.Active = recibeSignal;
_machineRepository.InsertOrUpdate(machine);
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
}
//[AbpAllowAnonymousAttribute]
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public async Task<List<string>> GetSignalRConnections()
{
return await _connection.InvokeAsync<List<string>>("GetConnectedUsers");
}
//[AbpAllowAnonymousAttribute]
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public async Task<List<string>> GetSignalRMachineConnections()
{
var tenantId = AbpSession.TenantId;
return await _connection.InvokeAsync<List<string>>("GetConnectedMachines", tenantId);
}
//[AbpAllowAnonymousAttribute]
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public async Task<List<string>> GetAvailableApplicationsLogs(string machineName)
{
var tenantId = AbpSession.TenantId;
return await _connection.InvokeAsync<List<string>>("GetAvailableApplicationsLogs", machineName, tenantId);
}
//[AbpAllowAnonymousAttribute]
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public async Task<IActionResult> GetServiceLog(string machineName, string serviceName)
{
var tenantId = AbpSession.TenantId;
var pathlog = await _connection.InvokeAsync<string>("GetServiceLog", machineName, tenantId, serviceName);
FileStreamingAppService fileStreamingAppService = new FileStreamingAppService(_fileProvider);
return await fileStreamingAppService.DownloadFile(pathlog.Split("@")[1]);
}
//[AbpAllowAnonymousAttribute]
[AbpAuthorize(AppPermissions.Pages_Administration_Users)]
public async Task UpdateApplicationsLogLevel(string machineName, string logLevel)
{
var tenantId = AbpSession.TenantId;
await _connection.InvokeAsync<List<string>>("SendUpdateApplicationsLogLevel", machineName, logLevel, tenantId);
}
#endregion
Because i need to update machines date (last login and last logout) when the machine disconnected to SignalR. In this static class (add in sistem with singleton) I define the client to connected to SignalR and your events subscrived. This signalR client pass to MachineAppService for send message to machines.
Could you tell me what the injection of dependencies from the static class should be like or give me a new idea?
Thanks for all.
Regards
I want to call a AppService from a static Class. This Static Class is defined in a Web.Host project.
AppService:
public interface ISignalRExtensionAppService : IApplicationService { Task<bool> Create(CreateMachineDto input); }
public class SignalRExtensionAppService : ISignalRExtensionAppService
{ public ILogger log { get; set; } private IDbContextProvider<GenTimeDbContext> _sampleDbContextProvider;
public SignalRExtensionAppService(IDbContextProvider<myDbContext> sampleDbContextProvider)
{
_sampleDbContextProvider = sampleDbContextProvider;
log = NullLogger.Instance;
}
public async Task<bool> Create(CreateMachineDto input)
{
try
{
log.Debug(string.Format("Machine: {0} with TenantId is {1} send: {2} - {3}", input.Name, input.TenantId, input.LastLogin, input.LastLogin));
using (var context = _sampleDbContextProvider.GetDbContext())
{
var machine = context.Machines.Where(x => x.Name == input.Name && x.TenantId == input.TenantId).FirstOrDefault();
machine.LastLogin = input.LastLogin;
machine.LastLogout = input.LastLogout;
context.SaveChanges();
}
return true;
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
return false;
}
}
public async Task<string> GetMachineName(int input)
{
string result = string.Empty;
try
{
log.Debug(string.Format("MachineId: {0}.", input));
using (var context = _sampleDbContextProvider.GetDbContext())
{
var machine = context.Machines.Where(x => x.Id == input).FirstOrDefault();
result = machine.Name;
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
return result;
}
- Static Class:
private static SignalRExtensionAppService _signalRExtensionAppService;
public static void AddSignalR(this IServiceCollection services, IConfiguration configuration)
{
var url = configuration["SignalR:Url"];
_signalRExtensionAppService = signalRExtensionAppService(); **<-- Error How to pass IDbContextProvider<myDbContext> sampleDbContextProvider**
*************************************
// Call to staic class services.AddSignalR(_appConfiguration);
how to pass IDbContextProvider<myDbContext> sampleDbContextProvider or IRepository<Application> _applicationRepository when make a new?
Thanks for all
Regards
When app installed in Android 9.0 (Samsung A40) crash when try to mount menu (MenuProvider.cs). NOT crash in Android 9.0 EMULATOR, only in device.
I need really help, please! (tell me what you need to know what's happening)
Yes! When methods are with "AppPermissions.Pages_Administration_Users" permission, the response is "current user did not login the application".
We are using Identity with IdentityModel (OpenId connection OAUTH), not Microsoft Identity... how the mobile app get the Token? And why using methods in web all is fine, but not in mobile?
The service require authorization, but I tested it with Authorization.Users and Anonymous decorators... Always NULL in AbpSession
Have a trouble:
My project have a X service in [MyProject].Application.Services with override GetAll and Create methods.
Other values sent from mobile to service are inserted well, just AbpSession values always null. No errors appear, only fields CreatorUserId and AbpSession.TenantId as NULL.
Why from mobile app (emulator) can't access to AbpSession? What am I doing wrong? Need help
Thanks!
After publish on IIS server the webapi (running in port 8075) works fine and swagger login receiving all data in GetCurrentLoginInformations, but webapp (running in port 8076) can't login (when attempt it return to login page again) because user return null.
You can see urls, configs, json below If Log needed tell me where to upload it for review
http://name:8075 (webapi)
http://name:8076 (webapp)
appsettings.json
{ "ConnectionStrings": { "Default": "Server=dbname;Database=my-DB;User Id=usr;Password=--------------;Max Pool Size=50000;" }, "AbpZeroLicenseCode": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Abp": { "RedisCache": { "ConnectionString": "localhost", "DatabaseId": -1 } }, "App": { "ServerRootAddress": "http://name:8075/", "ClientRootAddress": "http://name:8076/", "CorsOrigins": "http://*.mycompany.com,http://localhost:4201,http://localhost:49152,http://name:8076,http://localhost:8076", "SwaggerEndPoint": "/swagger/v1/swagger.json", "AllowAnonymousSignalRConnection": "true" }, "Authentication": { "Facebook": { "IsEnabled": "false", "AppId": "", "AppSecret": "" }, "Google": { "IsEnabled": "false", "ClientId": "", "ClientSecret": "", "UserInfoEndpoint": "https://www.googleapis.com/oauth2/v2/userinfo" }, "Microsoft": { "IsEnabled": "false", "ConsumerKey": "", "ConsumerSecret": "" }, "OpenId": { "IsEnabled": "false", "ClientId": "", "Authority": "", "LoginUrl": "", "ValidateIssuer": "true" }, "WsFederation": { "IsEnabled": "false", "Authority": "", "ClientId": "", "Tenant": "", "MetaDataAddress": "" }, "JwtBearer": { "IsEnabled": "true", "SecurityKey": "ProjectNameDemo_8CFB2EC534E14D56", "Issuer": "ProjectNameDemo", "Audience": "ProjectNameDemo" } }, "Twilio": { "AccountSid": "", "AuthToken": "", "SenderNumber": "" }, "Recaptcha": { "SiteKey": "6LfD-wUTAAAAACULAVXvL61K0w02RIsjhI8EyiS-", "SecretKey": "6LfD-wUTAAAAADm3h7vomd9FtaAlAwexki29BtXC" }, "IdentityServer": { "IsEnabled": "true", "Authority": "http://name:8075/", "ApiName": "default-api", "ApiSecret": "secret", "Clients": [ { "ClientId": "client", "AllowedGrantTypes": [ "password" ], "ClientSecrets": [ { "Value": "def2edf7-5d42-4edc-a84a-30136c340e13" } ], "AllowedScopes": [ "default-api" ] }, { "ClientId": "demo", "ClientName": "MVC Client Demo", "AllowedGrantTypes": [ "hybrid", "client_credentials" ], "RequireConsent": "true", "ClientSecrets": [ { "Value": "def2edf7-5d42-4edc-a84a-30136c340e13" } ], "RedirectUris": [ "http://openidclientdemo.com:8001/signin-oidc" ], "PostLogoutRedirectUris": [ "http://openidclientdemo.com:8001/signout-callback-oidc" ], "AllowedScopes": [ "openid", "profile", "default-api" ], "AllowOfflineAccess": "true" } ] }, "elasticsearch": { "index": "events", "url": "http://docker.dev.sasi.com.es:9200/", "user": "elastic", "pass": "changeme" }, "SignalR": { "Url": "http://name:8075/commeventoslog/" }, "Payment": { "PayPal": { "IsActive": "true", "Environment": "sandbox", "BaseUrl": "https://api.sandbox.paypal.com/v1", "ClientId": "", "ClientSecret": "", "DemoUsername": "", "DemoPassword": "" }, "Stripe": { "IsActive": "true", "BaseUrl": "https://api.stripe.com/v1", "SecretKey": "", "PublishableKey": "", "WebhookSecret": "" } } }
appsettings.Production.json
{ "ConnectionStrings": { "Default": "Server=name; Database=my-DB; User=usr; Password=------------;" }, "App": { "ServerRootAddress": "http://name:8075/", "ClientRootAddress": "http://name:8076/", "CorsOrigins": "http://*.mycompany.com,http://localhost:4201,http://localhost:49152,http://name:8076,http://localhost:8076", "SwaggerEndPoint": "/swagger/v1/swagger.json", "AllowAnonymousSignalRConnection": "true" } }
appsettings.Starting.json
{ "ConnectionStrings": { "Default": "Server=name; Database=my-DB; User=usr; Password=--------------;" }, "App": { "ServerRootAddress": "http://name:8075/", "ClientRootAddress": "http://name:8076/", "CorsOrigins": "http://*.mycompany.com,http://localhost:4201,http://localhost:49152,http://name:8076" } }
TokenAuth/Authenticate result
{ "result":{ "accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzIiwibmFtZSI6ImFkbWluIiwiQXNwTmV0LklkZW50aXR5LlNlY3VyaXR5U3RhbXAiOiJFU1hIWFBRMkNDWE0zUEZOUFFSU1BLSjVFSkJCNUdFSiIsInJvbGUiOiJBZG1pbiIsImh0dHA6Ly93d3cuYXNwbmV0Ym9pbGVycGxhdGUuY29tL2lkZW50aXR5L2NsYWltcy90ZW5hbnRJZCI6IjIiLCJqdGkiOiIxNmY2MmQ3ZC05MGZiLTRjMmItOWNmZi0xM2ZkOTRlNjI0NjAiLCJpYXQiOjE1NTkyMjM2MTcsInRva2VuX3ZhbGlkaXR5X2tleSI6ImJiMjFjMjc3LTE2MDAtNDk3MS1iMWIyLWMwNjU4YTY3ZjkxMSIsInVzZXJfaWRlbnRpZmllciI6IjNAMiIsIm5iZiI6MTU1OTIyMzYxNywiZXhwIjoxNTU5MzEwMDE3LCJpc3MiOiJHZW5UaW1lRGVtbyIsImF1ZCI6IkdlblRpbWVEZW1vIn0.IdZl4AbQklvXpgeOcw-XO3b2md7rajkjtojtGhWtfCg", "encryptedAccessToken":"wNYmO41/48SHNstaLVXxHCCre29BZQl1NhC6NM3R3rwZiL572M4gBaHf6sHsTGZftncpoxsQRCchWFIbFohtelZlOk+oXOvXRR/lwamT8lfGbrgzSUhC5rffkuz/PKEWTuaVKXr0iPHIMrVG6ZDWPtdavXryMCISaxPIYPLjVyAugdk791PV3V7zHOcebtcNNfFZS4szg4fgWzLzZJR9yDzFJ9j96B9MvkOTT3KlAZeBmhTRBsLZSwCNWQJVzkkI9p+MovTT3o7OV8Xjnp5xaXHhnjfYOBs3VkLNHfX9phATEpYT8CjUsldq9KLi7UY0eQpLu05BNlufHzOjufS0IfHT0QEN9ITNNDEKlM1vwdFcl9DfQ16eYRelpAQlwXw+rLMhsLZA2g3oxJnja1/vgz6Jho3Uf1bAw4T/4Jbhcc2nM+hbikx+6swL9B/u3DGDZQV8GGN4kamYUKqcPP0w/vHrnr1cyPMtygH1IfhfkZ1Lbxb8zLVGE2OsZendD94KibbhQCAtzBQ6jNdYdGdaAGctEJC3j8GnhNsQRpBk21Ugzj/nP245radSUJG8ChH8VhPlu1lMqx4s9L/V3OXZQgvuAXG1hShhh5joTcj9DeCPch21x+AG4cIIM+7IuuckAsLKKB5DSkt5c8pJS7yFsgg3zujBF4V8MgxpvmbS1jc5zfHJ+TJ9J9xc2hF662O6yHXcKt5VLlWGEaCywlvOp2okCxvBq0L2HfxEK1FMBqbiUUv4RZ9vpDRvPAGuAnhS4HuAl6zExTwy6x8uevwvOmuI6tFOD53EJWmJaB3MFRM=", "expireInSeconds":86400, "shouldResetPassword":false, "passwordResetCode":null, "userId":3, "requiresTwoFactorVerification":false, "twoFactorAuthProviders":null, "twoFactorRememberClientToken":null, "returnUrl":null, "refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzIiwibmFtZSI6ImFkbWluIiwiQXNwTmV0LklkZW50aXR5LlNlY3VyaXR5U3RhbXAiOiJFU1hIWFBRMkNDWE0zUEZOUFFSU1BLSjVFSkJCNUdFSiIsInJvbGUiOiJBZG1pbiIsImh0dHA6Ly93d3cuYXNwbmV0Ym9pbGVycGxhdGUuY29tL2lkZW50aXR5L2NsYWltcy90ZW5hbnRJZCI6IjIiLCJqdGkiOiJmZWFmNTNlOC1mZjQwLTRmYWQtODcwNi1mZjRiNjkyNjczMmEiLCJpYXQiOjE1NTkyMjM2MTcsInRva2VuX3ZhbGlkaXR5X2tleSI6IjNkNzZlMTIyLWIyY2YtNDlmZS1iOGI2LTdlNWM5ZWZjN2UyNiIsInVzZXJfaWRlbnRpZmllciI6IjNAMiIsIm5iZiI6MTU1OTIyMzYxNywiZXhwIjoxNTkwNzU5NjE3LCJpc3MiOiJHZW5UaW1lRGVtbyIsImF1ZCI6IkdlblRpbWVEZW1vIn0.qmCMO12ZfnPqizwBoqKhbj4-lx7YTqZHqRQmWwKDnDM" }, "targetUrl":null, "success":true, "error":null, "unAuthorizedRequest":false, "abp":true }
Session/GetCurrentLoginInformations result
{ "result":{ "user":null, "tenant":{ "tenancyName":"seidor", "name":"SEIDOR", "logoId":null, "logoFileType":null, "customCssId":null, "subscriptionEndDateUtc":null, "isInTrialPeriod":false, "subscriptionPaymentType":0, "edition":{ "displayName":"Standard", "trialDayCount":null, "monthlyPrice":null, "annualPrice":null, "isHighestEdition":true, "isFree":true, "id":1 }, "creationTime":"2019-05-21T10:45:33.0202391", "paymentPeriodType":0, "subscriptionDateString":"Unlimited", "creationTimeString":"5/21/2019", "id":2 }, "application":{ "version":"6.9.0.0", "releaseDate":"2019-05-30T11:38:59.4703924+02:00", "currency":"USD", "currencySign":"$", "allowTenantsToChangeEmailSettings":false, "features":{
}
},
"theme":{
"baseSettings":{
"theme":"default",
"layout":{
"layoutType":"fluid",
"contentSkin":"light2",
"themeColor":"blue",
"fixedBody":false,
"mobileFixedBody":false
},
"header":{
"desktopFixedHeader":true,
"mobileFixedHeader":true,
"headerSkin":"dark"
},
"menu":{
"position":"left",
"asideSkin":"dark",
"fixedAside":true,
"allowAsideMinimizing":true,
"defaultMinimizedAside":false,
"allowAsideHiding":false,
"defaultHiddenAside":false,
"submenuToggle":"Accordion"
},
"footer":{
"fixedFooter":true
}
},
"isLeftMenuUsed":true,
"isTopMenuUsed":false,
"isTabMenuUsed":false,
"allowMenuScroll":true
}
}, "targetUrl":null, "success":true, "error":null, "unAuthorizedRequest":false, "abp":true }
Thanks!