Signalr 1.0.1 Cross domain 404 error - asp.net-mvc

I have problem with Signalr cross domain usage. I have three different projects(applications) inside one solutions and use signalr to enable chat functionality among them. I have chat project that is separated for other three apps.
This is code from it:
HUB
[HubName("ChatHub")]
public class ChatHub : Hub
{
public void Send(PorukaViewModel message)
{
..do some code
Clients.All.addMessage(
... // returns feedback to clients
);
}
}
GlobalASAX
protected void Application_Start()
{
RouteTable.Routes.MapHubs(new HubConfiguration() { EnableCrossDomain = true });
}
And this is code from my clients apps,
Controller
string chatUrl = System.Configuration.ConfigurationManager.AppSettings["ChatUrl"] + "/signalr/hubs";
var connection = new HubConnection(chatUrl, useDefaultUrl: false);
IHubProxy myHub = connection.CreateHubProxy("ChatHub");
connection.Start().ContinueWith(task =>
{
if (task.IsFaulted)
{
//... I log error and stop connection
connection.Stop();
}
message = "some message";
myHub.Invoke("Send", message).Wait();
connection.Stop();
});
This all working fine on my localhost, but when I deploy it on IIS I have this error on connection.Start():
System.Net.WebException: The remote server returned an error: (404)
Not Found. at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult
asyncResult) at
Microsoft.AspNet.SignalR.Client.Http.HttpHelper.<>c__DisplayClass2.b__0(IAsyncResult
ar) at
System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult
iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean
requiresSynchronization)
I browsed all question and answers on stackoverflow but can't find any that would help me.
What am I doing wrong?
*NOTE
With jQuery I modified hubs.js and changed this code:
var signalrUrl = $("#chatUrl").val() + '/signalr';
...
signalR.hub = $.hubConnection(signalrUrl, { useDefaultPath: false });
and use this in my communication Views, this is working fine both on localhost and IIS.
Maybe problem is in this line?
signalR.hub = $.hubConnection(signalrUrl, { useDefaultPath: false });
In original /signalr/hubs it like this:
signalR.hub = $.hubConnection("/signalr", { useDefaultPath: false });
How can I do that from controller?

This code is incorrect:
string chatUrl = System.Configuration.ConfigurationManager.AppSettings["ChatUrl"] + "/signalr/hubs";
/SignalR/Hubs points to a Javascript proxy.
/signalr is the connection end point so the code should be:
string chatUrl = System.Configuration.ConfigurationManager.AppSettings["ChatUrl"];
Since the .NET client automatically appends the default /signalr URL.
More on the documentation here https://github.com/SignalR/SignalR/wiki/SignalR-Client-Hubs#hubconnection-api

Related

Connecting to Neo4j Aura with .NET Core 2.2 web api

I am trying to connect a to Neo4j Aura instance from a .NET core 2.2 web api. I understand I need the Neo4j .Net Driver v4.0.0-alpha01, but I do not seem to be able to connect. There aren't very many examples out there as this driver is new and so is Aura.
I keep getting:
Failed after retried for 6 times in 30000 ms. Make sure that your database is online and retry again.
I configure the driver as such
public void ConfigureServices(IServiceCollection services)
{
string uri = "neo4j://1234567.databases.neo4j.io:7687";//not actual subdomain
string username = "neo4j";
string password = "seeeeeeecret";//not actual password
services.AddCors();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSingleton(GraphDatabase.Driver(uri, AuthTokens.Basic(username, password)));
}
and in my test controller i run this
private async Task<string> Neo4JTestAsync()
{
string db = "MyDb";
string message = "TESTMESSAGE";
IAsyncSession session = _driver.AsyncSession(o => o.WithDatabase(db));
try
{
var greeting = session.WriteTransactionAsync(async tx =>
{
var result = tx.RunAsync("CREATE (a:Greeting) " +
"SET a.message = $message " +
"RETURN a.message + ', from node ' + id(a)",
new { message });
var res = await result;
return "return something eventually";
});
return await greeting;
}
catch (Exception e)
{
return e.Message; // throws "Failed after retried for 6 times in 30000 ms. Make sure that your database is online and retry again"
}
finally
{
await session.CloseAsync();
}
}
I can't get the exact error message you do - but I'm pretty sure this is due to encryption - one of the big differences between the 1.x and 4.x drivers is the default position on Encryption - which is now off by default.
So you'll want to change your initialisation to:
services.AddSingleton(GraphDatabase.Driver(uri, AuthTokens.Basic(username, password), config => config.WithEncryptionLevel(EncryptionLevel.Encrypted)));
That should get you going. Also - make sure you stick with the neo4j:// protocol, as that'll route you properly.
Have you tried bolt:// in the connection string?
string uri = "bolt://1234567.databases.neo4j.io:7687";//not actual subdomain

Check overall progress of Azure Job and send it to an ASP.NET View

I'm creating a website with ASP.NET MVC5, hosted on Azure.
My users may upload a video, and I'd like to create a progress bar or something indicating how much % of the upload / transcoding has been done.
I'm following this Microsoft tutorial and the videos are correctly uploaded.
However, they show these lines of code once the job is sumbitted to Azure :
job = job.StartExecutionProgressTask(
j =>
{
Console.WriteLine("Job state: {0}", j.State);
Console.WriteLine("Job progress: {0:0.##}%", j.GetOverallProgress());
},
CancellationToken.None).Result;
I'm trying to adapt it to show it on my webpage.
Question
However, I'm unable to "send" j.GetOverallProgress() to my view.
Can anyone explain how to do this ?
What I did so far
Install Microsoft.AspNet.SignalR package (v 2.4.1)
(first time using SignalR)
Add these lines in my view :
<script src="~/Scripts/signalR/jquery.signalR-2.4.1.js"></script>
<script src="~/signalr/hubs"></script>
<script type="text/javascript">
$(document).ready(function () {
var hub = $.connection.videoService;
$("#btnCreate").on("click", function () {
hub.client.displayProgress = function (data) {
console.log(data); //Nothing is logged
};
})
});
</script>
And these lines on my back-end : (VideoService.cs in \Services folder)
public class VideoService : Hub
{
public EncodeMyVideo(...)
{
/* [...] */
job = job.StartExecutionProgressTask(j => {
displayProgress(job);
}, CancellationToken.None).Result;
}
public double displayProgress(IJob job)
{
return job.GetOverallProgress();
}
}
In debug mode, it goes to displayProgress method but never send anything to the view.
As a aside note, I also tried ith this :
public void displayProgress(IJob job)
{
Clients.Caller.displayProgress(job.GetOverallProgress());
}
But I get this error :
Using a Hub instance not created by the HubPipeline is unsupported.
I'm very new with SignalR, and despite this SO answer, I don't really understand what the problem is.
What should I do to send job.GetOverallProgress(); into my view ?
displayProgress method runs in another thread so it does not share the same Context with the EncodeMyVideo method. So you need to use GlobalHost.ConnectionManager.GetHubContext<> to get your hub context and your client connections.
string callerId = Context.ConnectionId;
job = job.StartExecutionProgressTask(j => {
displayProgress(job, callerId);
}, CancellationToken.None).Result;
public void displayProgress(IJob job, string clientId)
{
//Access to your hub context outside the request context
GlobalHost.ConnectionManager.GetHubContext<VideoService>().Clients.Client(clientId).displayProgress(job.GetOverallProgress());
}
For reporting progress you may also check this Reporting progress from hub method invocations

ActiveMQ test connection

I am trying to test ActiveMQ connection and return a value. it crashes on line:
httpResponse = client.execute(theHttpGet);
It is not my code I am trying to debug it. Can anyone help me to understand why the code is using HttpGet?
public ActivemqBrokerInfo(String serverAddress, int port, String apiUrl, int timeout) {
// Default Activemq location
this.serverAddress = String.format("http://%s:%s/%s", serverAddress, port, apiUrl);
int timeoutInMs = timeout;
HttpClientBuilder builder = HttpClientBuilder.create();
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeoutInMs).build();
builder.setDefaultRequestConfig(requestConfig);
client = builder.build();
}
public ActivemqBrokerInfo(String serverAddress) {
this(serverAddress, DEFAULT_PORT, DEFAULT_API_URL, DEFAULT_TIMEOUT);
}
#Override
public boolean testConnection() {
HttpGet theHttpGet = new HttpGet(serverAddress);
theHttpGet.addHeader("test-header-name", "test-header-value");
HttpResponse httpResponse = null;
try{
httpResponse = client.execute(theHttpGet);// Code is crashing on this line
} catch (IOException ex){
LOGGER.error("Broker down: ", ex);
}
return httpResponse != null;
}
When ActiveMQ runs is normally starts an embedded web server. This web server is used to host the web admin console as well as the Jolokia endpoint which acts as an HTTP facade in front of the broker's MBeans. In other words, any client can send HTTP requests to specially formed URLs on the broker to get results from the underlying management beans. This is exactly what your bit of code appears to be doing. It appears to be sending an HTTP request to the Jolokia endpoint (i.e. api/jolokia) in order to determine if the broker is alive or not.
Based on the information provided it is impossible to determine why testConnection() is not returning successfully since you've included no information about the configuration or state of the broker.
I recommend you add additional logging to see what may be happening and also catch Exception rather than just IOException.

No errors are being raised when unsuccessfully writing to Azure service bus

When writing a message to the Azure Service Bus (using Microsoft.Azure.ServiceBus standard library, not the .Net Framework version) it works fine. However, when switching networks to a network that blocks that traffic and running it again I would expect an error being raised by SendAsync yet no error is thrown, therefor the function considers the send successful even though it is not.
Am I missing some logic to make sure that errors do get raised and trapped, it seems to be inline with all the examples I have seen.
I have tried this possible solution ..
Trouble catching exception on Azure Service Bus SendAsync method
.ContinueWith(t =>
{
Console.WriteLine(t.Status + "," + t.IsFaulted + "," + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);
.. and at no point does ContinueWith get hit.
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
public ActionResult<Boolean> Post(Contract<T> contract)
{
Task.Run(() => SendMessage(contract));
// Other stuff
}
private async Task<ActionResult<Boolean>> SendMessage(Contract<T> contract)
{
JObject json = JObject.FromObject(contract);
Message message = new Message();
message.MessageId = Guid.NewGuid().ToString();
message.ContentType = ObjectType;
message.PartitionKey = ObjectType;
message.Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(contract));
foreach (KeyValuePair<String, String> route in DataRouting)
{
JToken jToken = json.SelectToken(route.Value);
if (jToken != null)
{
message.UserProperties[route.Key] = jToken.Value<String>();
}
else
{
String routeError = $"Could not find routing information in request for: {route.Key} in {route.Value}";
Logger.LogError(routeError);
return new UnprocessableEntityObjectResult(routeError);
}
}
// Send the message
try
{
await topicClient.SendAsync(message);
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}
return new OkObjectResult(true);
}
I expect that the error trap would be hit if the SendAsync fails to send the message. However it essentially fire and forgets, the message send is blocked by the firewall but is never reported to the caller by throwing an error.
Ok, found the answer, but I will leave this out there in case anyone else does this to themselves. It was down to my general muppetry when putting the MVC Controller together. Set async on the Post action and configure the await on the send. Obvious really but I missed it.
public virtual async Task<ActionResult<Boolean>> Post(Contract<T> contract){}
...
// Send the message
try
{
await topicClient.SendAsync(message).ConfigureAwait(false);
return new OkObjectResult(true); // Success if we got here
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}

How to better troubleshoot this 500 Error in MVC Web API

I have an MVC Web API project that I am working on. I created a controller with an action. I am able to hit the action properly using Postman, but when an external system tries to reach my controller, it gets a 500 error. The owner of the external service cannot give me any details beyond that, they can only retry the request.
Here is one of the log entries of their requests in IIS log
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2017-02-15 20:38:58 192.168.2.34 POST /Route/to/actionName 8002 - 192.168.2.37 Apache-HttpClient/4.5.2+(Java/1.8.0_102) - 500 0 0 146
First I thought may be the action is being hit, so I added an exception handler and added logging.
[Route("actionName")]
[HttpPost]
public IHttpActionResult actionName(MessageModel message)
{
try
{
// code to handle the action
}
catch (Exception e)
{
// Code to log exception in the log file
}
}
Tried above and saw nothing in the log, I have run tests for failed requests to make sure the above exception handler logs and it does.
So the next thing I decided to do was to handle application level errors in Global.asax and log exception there.
protected void Application_Error(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = SomeMethodToReadRequestContentsInString();
var service = new SomeExceptionLoggingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("Unknown error occurred");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And to my surprise, nothing in the log file.
So then I decided to log ALL Post requests and see if I register ANYTHING in the log.
protected void Application_EndRequest(object sender, EventArgs e)
{
if (Request.HttpMethod == "POST")
{
var request = Helper.ReadStreamUnknownEncoding(Request.InputStream);
var service = new InterfaceTestingService();
var exception = Server.GetLastError();
if (exception == null)
{
exception = new ApplicationException("No Error in this request");
}
service.LogException(exception, Request.UserHostAddress, Request.UserAgent, request);
}
}
And again, nothing!
How do I catch this bug? My goal is to see the Content-Type, and contents.
I tried to add a Custom Field in IIS log settings to include `Content-Type', but the log files still don't have that.
I added a handler for Application_BeginRequest logging everything I did in Application_EndRequest. And it turns out, the content-length was zero, and there was no content. I also restarted IIS Web Server to get it to log custom fields too.
What's strange is that if I send empty content through Postman, I get the action code executed but for some reason when they do it, it doesn't.

Resources