Hi,
I have downloaded the sample oData project from <a class="postlink" href="https://github.com/aspnetboilerplate/sample-odata">https://github.com/aspnetboilerplate/sample-odata</a> I re-stored all the nuget packages.
Now when I run the Update-Database command from package manager console, it throws the following error:
No migrations configuration type was found in the assembly 'AbpODataDemo.EntityFramework'. (In Visual Studio you can use the Enable-Migrations command from Package Manager Console to add a migrations configuration).
Please advise....
Hi,
Please ignore this post...It was my mistake.....solved now....
Hi,
I am using Hangfire for background job.
public override void Execute(GeneratePayloadAndSendToMobileArgs generatePayloadAndSendToMobileArgs)
{
Task SendDataToMobileTask = Task.Run(() => SendDataToMobile(generatePayloadAndSendToMobileArgs));
SendDataToMobileTask.Wait();
}
private async Task SendDataToMobile(GeneratePayloadAndSendToMobileArgs generatePayloadAndSendToMobileArgs)
{
try
{
using (_abpSession.Use(generatePayloadAndSendToMobileArgs.TenantId, generatePayloadAndSendToMobileArgs.UserId))
{
using (var unitOfWork = _unitOfWorkManager.Begin())
{
Dictionary<RetailObjectId, ICRUDAppService> CRUDAppServices = new Dictionary<RetailObjectId, ICRUDAppService>();
List<PayloadData> PayloadsToSend = new List<PayloadData>();
Dictionary<long, string> PayloadsToSave = new Dictionary<long, string>();
var Payloads = (from Rep in _ReplicationTransactionMobileRepository.GetAll()
select new
{
SequenceNo = Rep.Id,
SourceType = (RetailObjectId)Rep.SourceType,
SourceKey = Rep.SourceKey,
OperationType = (OperationType)Rep.OperationType,
Payload = Rep.Payload,
}).ToList().Take(500);
foreach (var item in Payloads)
{
PayloadData PayloadToSend = new PayloadData()
{
SequenceNo = item.SequenceNo,
SourceType = item.SourceType,
SourceKey = item.SourceKey,
OperationType = item.OperationType,
};
if (!string.IsNullOrEmpty(item.Payload))
PayloadToSend.Payload = GetPayload(item.SourceType, item.Payload);
else
{
string PayloadToSave = GeneratePayload(item.SequenceNo, item.SourceType, item.SourceKey, CRUDAppServices);
PayloadToSend.Payload = GetPayload(item.SourceType, PayloadToSave);
PayloadsToSave.Add(item.SequenceNo, PayloadToSave);
}
PayloadsToSend.Add(PayloadToSend);
PayloadResult obj = new PayloadResult();
obj.result = PayloadsToSend;
List<ConnectedClient> connectedClients = AppStatic.ConnectedClients.Where(p => p.TenantId == generatePayloadAndSendToMobileArgs.TenantId).ToList();
if (connectedClients.Count() > 0 && PayloadsToSend.Count > 0)
{
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings();
jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
await _iVend365HubContext.Clients.All.SendAsync("GetDeltaQueue", JsonConvert.SerializeObject(obj, jsonSerializerSettings));
}
}
//Delete the Successfully send records
_iVendRepository.ExecuteQuery("Delete From RepReplicationTransactionMobileDetail Where ProcessStatus = 1");
_iVendRepository.ExecuteQuery("Delete From RepReplicationTransactionMobile Where SequenceNo Not In (Select RepReplicationTransactionMobileSequenceNo From RepReplicationTransactionMobileDetail)");
//Save the newely generated Payload in DB
foreach (KeyValuePair<long, string> PayloadToSave in PayloadsToSave)
{
ReplicationTransactionMobile replicationTransactionMobile = _ReplicationTransactionMobileRepository.Get(PayloadToSave.Key);
replicationTransactionMobile.Payload = PayloadToSave.Value;
_ReplicationTransactionMobileRepository.Update(replicationTransactionMobile);
}
unitOfWork.Complete();
}
}
}
catch (Exception ex)
{
}
}
In the above code, at following line, it throws the error, "There is already an open DataReader associated with this Command which must be closed first." Any idea, what could be wrong here?
var Payloads = (from Rep in _ReplicationTransactionMobileRepository.GetAll()
select new
{
SequenceNo = Rep.Id,
SourceType = (RetailObjectId)Rep.SourceType,
SourceKey = Rep.SourceKey,
OperationType = (OperationType)Rep.OperationType,
Payload = Rep.Payload,
}).ToList().Take(500);
Hi,
I think, I have resolved it by using encodeURIComponent in the javascript client to encode the encrypted access token...
Anyway...thanks for your support....
Hi,
Let me try to explain you once again. My JavaScript client was successfully able to connect to My SignalR Hub and the data exchange between client and server was happening successfully till the time there is no authentication implemented.
Now to implement client authentication, I did the following:
In the CitiXsys.iVend365.Web.Mvc Project's AuthConfigurer.cs class, I add the following:
public static void Configure(IServiceCollection services, IConfiguration configuration)
{
.....
if (bool.Parse(configuration["Authentication:JwtBearer:IsEnabled"]))
{
.......
options.Events = new JwtBearerEvents
{
OnMessageReceived = QueryStringTokenResolver
};
}
}
/* This method is needed to authorize SignalR javascript client.
* SignalR can not send authorization header. So, we are getting it from query string as an encrypted text. */
private static Task QueryStringTokenResolver(MessageReceivedContext context)
{
if (!context.HttpContext.Request.Path.HasValue ||
!context.HttpContext.Request.Path.Value.StartsWith("/signalr"))
{
//We are just looking for signalr clients
return Task.CompletedTask;
}
var qsAuthToken = context.HttpContext.Request.Query["enc_auth_token"].FirstOrDefault();
if (qsAuthToken == null)
{
//Cookie value does not matches to querystring value
return Task.CompletedTask;
}
//Set auth token from cookie
try
{
context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase);
}
catch (Exception ex)
{
}
return Task.CompletedTask;
}
Also In My Hub Class, I added the attribute AbpAuthorize.
[AbpAuthorize]
public class iVend365Hub : AbpCommonHub
{
public iVend365Hub(IOnlineClientManager onlineClientManager, IClientInfoProvider clientInfoProvider) : base(onlineClientManager, clientInfoProvider)
{
}
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
ConnectedClient DisConnectedClient = AppStatic.ConnectedClients.Where(p => p.ConnectionId == Context.ConnectionId).SingleOrDefault();
AppStatic.ConnectedClients.Remove(DisConnectedClient);
Clients.All.SendAsync("PrintConnectedPOS", "POS - " + DisConnectedClient.POSKey + " DisConnected");
return base.OnDisconnectedAsync(exception);
}
public void RegisterPOS(Int32 TenantId, string POSKey)
{
ConnectedClient connectedClient = new ConnectedClient() { TenantId = TenantId, POSKey = POSKey, ConnectionId = Context.ConnectionId };
AppStatic.ConnectedClients.Add(connectedClient);
Clients.All.SendAsync("PrintConnectedPOS", "POS - " + POSKey + " Connected");
}
}
Now From Postman, I called the API <a class="postlink" href="http://localhost:62114//api/TokenAuth/Authenticate">http://localhost:62114//api/TokenAuth/Authenticate</a> and get the accesstoken and encryptedAccessToken.
Now from my client I am trying the connect to SignalR Hub by passing encryptedAccessToken as query string as below:
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:62114/signalr?enc_auth_token=wNYmO41/48SHNstaLVXxHCCre29BZQl1NhC6NM3R3rzpXtPQxVzH6jEzA/QhXFN5tu6Fk7pO53uppm1mVXMZgxbyRVz26dnepi/FyB6axBY+6gq1GL+uRQgoiFUCjRN2p8w6LevViwKlHyWZZJZO1DGVSjAi1m2U+og9pkHw9/QZzDt3yiLMoYW1WDdaXPnlFLgt0N06nDVJ/TNUnhw0BCL43otzv+OMKuLeY+h0rGYDeO90t9A/K6VhhzUXsg1AnxPiqcPpiycwoLyZAZ53/kzTppy8m3SYqaKUsjOESlkAY8kF2r7y154j9qEUcLk9utfC3PSRp0oSuNrm4VSVguDREewfyWbN2sKRaHtlXs5UxIgBWyA348/T9keWz4iRdlPaw7R66Toe+whj4AhIwXhBIQMqxokrK1Sq2LBTHHwJPAUsTkzsTwP1v0/VcSC9oGwxy27ovrSXKN9G5/i43T5nZW5vR+X2Q4SVFS4wi03ifhySoobT6PgEUGaET9Xp62cBKgzEM589+abpKPMhAs4533XlfdfWRr6UxNUUF0LMuya3RB2NCE1h6ccRo0vujM9DMiKxU04lQ5ezjQV6k1lqFx0CjsCZEscMH91ICvjAuAnUXkHpCeNyfJl5Om+Xen1Ef57GeI0WV/5Rj6h6FJt+z8xDXCZJ8ikvpQe+tjjvX+vAfQdyR5nFgHC/vCNiab0x/qnWgJyoQOcXxMUZ43HXsRIruWCre/gpHvfEysGKsk7V3PLpdgESTQVNniZPHs7EypH8r8+T9VRiR1X964QUmqnaBMn3pNkrMBm1gEqyB1sP7HNlz3dLvjRRUX3JcD2/Pe5elhZBjnYRLu8Ay7pJaEzXgEeJ3cRGkq8DbxXZEg5O+f3+VjYssQDjesGGg8ZDwaBDriBSWjOtvnw7OFqvD7qk4xzXqFZpIRnqkJ/70mLCFfTGTxpjMWnFMTu9xh8Snm2/uPex48biHG30f4BXw0xmW2xZ521GIRdgFIE=")
.configureLogging(signalR.LogLevel.Information)
.build();
connection.start().catch(err => console.error(err.toString()));
But it throws the error in the following code:
context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase);
The error returned is: Invalid length for a Base-64 char array or string.
Please help...
Here is my complete code of SignalR. The question is when JavaScript client runs, it does not hit the breakpoint at QueryStringTokenResolver function of AuthConfigurer class.
I am sure, I must be missing something. Please advise....
----------------------------Application Service iVend365ApplicationModule.cs---------------------------- [DependsOn( typeof(iVend365CoreModule), typeof(AbpAspNetCoreSignalRModule) )] public class iVend365ApplicationModule : AbpModule { …… …... } ----------------------------Application Service iVend365Hub.cs---------------------------- public override Task OnConnectedAsync() { return base.OnConnectedAsync(); }
public override Task OnDisconnectedAsync(Exception exception)
{
ConnectedClient DisConnectedClient = AppStatic.ConnectedClients.Where(p => p.ConnectionId == Context.ConnectionId).SingleOrDefault();
AppStatic.ConnectedClients.Remove(DisConnectedClient);
Clients.All.SendAsync("PrintConnectedPOS", "POS - " + DisConnectedClient.POSKey + " DisConnected");
return base.OnDisconnectedAsync(exception);
}
public void RegisterPOS(Int32 TenantId, string POSKey)
{
ConnectedClient connectedClient = new ConnectedClient() { TenantId = TenantId, POSKey = POSKey, ConnectionId = Context.ConnectionId };
AppStatic.ConnectedClients.Add(connectedClient);
Clients.All.SendAsync("PrintConnectedPOS", "POS - " + POSKey + " Connected");
}
----------------------------MVC Web Startup.cs---------------------------- public IServiceProvider ConfigureServices(IServiceCollection services) { ……. services.AddCors(options => options.AddPolicy("CorsPolicy", builder => { builder .AllowAnyHeader() .AllowAnyMethod() .AllowAnyOrigin() .AllowCredentials(); }));
services.AddSignalR(options =>
{
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
});
…………….
…………….
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ………… app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<iVend365Hub>("/signalr");
});
………………
…………..
}
-----------------MVC Web AuthConfigurer.cs---------------------------- private static Task QueryStringTokenResolver(MessageReceivedContext context) { if (!context.HttpContext.Request.Path.HasValue || !context.HttpContext.Request.Path.Value.StartsWith("/signalr")) { //We are just looking for signalr clients return Task.CompletedTask; }
var qsAuthToken = context.HttpContext.Request.Query["enc_auth_token"].FirstOrDefault();
if (qsAuthToken == null)
{
//Cookie value does not matches to querystring value
return Task.CompletedTask;
}
//Set auth token from cookie
context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase);
return Task.CompletedTask;
}
----------------------JavaScript Client (Another Project)-------------------- <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> <script src="Scripts/signalr.js"></script> <script> const connection = new signalR.HubConnectionBuilder() //.withUrl("http://ivend365retail-signalrtest.azurewebsites.net/signalr?enc_auth_token=ABCD") .withUrl("http://localhost:62114/signalr") .configureLogging(signalR.LogLevel.Information) .build();
connection.start().then(function () {
connection.send("RegisterPOS", 1018, "418307399342882834");
//connection.send("RegisterPOS", 972, "441464738128330770");
});
connection.on("GetDeltaQueue", function (message) {
console.log(message);
});
connection.on("PrintConnectedPOS", function (message) {
console.log(message);
});
</script>
</body> </html>
Hi,
The link you shared is not opening and throwing 404 error.
Hi,
I am using ABP 3.6.2. Could you please advise me (or provide me link), how can I implement authentication? Please be aware, in my case the client here would be a third party application.
One way, in my mind is, let client call the Authenticate API of my application which will return him a token and then let the client connect to our signalr hub by passing that token. But I don't know how should I validate that token in my signalr Hub onConnected event?
Please help....
Regards, Mahendra
Hi,
In ABP version 3.6.1, the following Javascript Client was working perfectly fine. But, since when we update the ABP to 3.6.2, it is not working.... In the following code, it throws the error: "signalr.min.js:15 Uncaught (in promise) WebSocket is not in the OPEN state"
Is there a new signalr.min.js file for ABP 3.6.2, If yes, please let me know the path from where I can download the same.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body>
<script src="Scripts/jquery-1.6.4.js"></script>
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<script src="http://localhost:62114/lib/signalr-client/signalr.min.js"></script>
<script>
var connection = new signalR.HubConnection('http://localhost:62114/signalr', { transport: signalR.TransportType.WebSockets });
connection.start().then(function () {
connection.send("RegisterPOS", 1018, "418307399342882834");
});
</script>
</body> </html>
Please advise... Regards, Mahendra
Also, last time you provided me a ABP GitHub path to download signalr.min.js file.
since we have upgraded the ABP to 3.6.2. I am sure the above file (signalr.min.js) also must have got changed.
Could you please provide me the path from where I can download this file.....