The users of my Silverlight application will access the server via a VPN connection. Thus, the built in NetworkInterface.GetIsNetworkAvailable is of no use.
I tried 2 different methods for checking connection to my server; WebClient and a WCF service.
As for the service, I tried the following method. I can't see how I would use a regular service call since the return handler would never hit.
var ping = new PingServiceClient();
ping.InnerChannel.Open( new TimeSpan(1500) );
var result = ping.State == CommunicationState.Opened;
Using WebClient, I tried this:
var client = new WebClient();
client.OpenReadCompleted += (s, e) => { MessageBox.Show( "Returned from server" ); };
client.OpenReadAsync( new PingServiceClient().Endpoint.Address.Uri );
In both cases, the results were the same (indicates connected) whether or not I was connected to the server (I pushed the samples to the live server and connected/disconnected using the VPN client.
The next thing I would try is sockets, but just getting a working sample is beyond difficult. Before going down that road any further, is there some other way of accomplishing this?
The WebClient will probably return completed regardless. You'll need to check if there was an error in the request.
var client = new WebClient();
client.OpenReadCompleted += (s,e) =>
{
if (e.Error == null)
{
MessageBox.Show("Returned from server");
}
}
client.OpenReadAsync( new PingServiceClient().Endpoint.Address.Uri );
I placed a small text file on the server and read it's contents. So this test worked reliably [edit: see comment]:
var client = new WebClient();
client.OpenReadCompleted += (s, e) =>
{
if ( e.Error == null )
{
var bytesReceived = new byte[ e.Result.Length ];
e.Result.Read( bytesReceived, 0, 50 );
var result = Encoding.UTF8.GetString( bytesReceived, 0, bytesReceived.Length );
if ( result.Contains( "pingback" ) )
{
MessageBox.Show("Server up");
}
else
{
MessageBox.Show( "Server down" );
}
}
else
{
MessageBox.Show("Server down");
}
};
var uri = string.Format( "{0}{1}{2}{3}{4}{5}", App.Current.Host.Source.Scheme, "://", App.Current.Host.Source.DnsSafeHost, ":", App.Current.Host.Source.Port, "/Ping.txt" );
client.OpenReadAsync( new Uri(uri) );
Related
I'm teaching myself Blazor and have run into this conundrum, where I get this error:
{"No connection could be made because the target machine actively refused it."}
The uri I call is this one:
api/employee
However, when use the full uri, such as this:
https://localhost:44376/api/employee
I get no errors at all.
Even though this is just a practice project, I'd still prefer to use a relative uri without a port number, but am not sure how to make it work.
Here's the method where I am making these calls:
public async Task<IEnumerable<Employee>> GetAllEmployees()
{
bool isEmployeeListEmpty = true; ;
IEnumerable<Employee> employeeList = null;
try
{
//string uriEmployeeList = $"https://localhost:44376/api/employee";
string uriEmployeeList = $"api/employee";
var employees = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
if (employees != null)
{
isEmployeeListEmpty = false;
employeeList = await JsonSerializer.DeserializeAsync<IEnumerable<Employee>>
(await _httpClient.GetStreamAsync(uriEmployeeList), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
else
{
isEmployeeListEmpty = true;
}
}
catch (Exception ex)
{
Console.WriteLine("An exception occurred inside the GetAllEmployees() method of the EmployeeDataService class");
Console.WriteLine(ex.Message);
}
if (!isEmployeeListEmpty)
return employeeList;
else
return null;
}
I am doing this all on one machine with IIS Express.
UPDATE
Thank you all for your help and suggestions. It turned out that I had the ssl port defined as 44376 in the lauchSettings.json, while I had the base addresses in Startup.cs file set as https://localhost:44340/ for all three HttpClient objects I use. I changed the port in each of the base addresses to 44376 to match the 44376 port I have set up in the launchSettings.json file, and everything now works with the relative/abbreviated uri strings.
Please see if api and web project are set under "Multiple startup" and both are ACTION : "start" are not (Right click on Solution > Set Startup Projects), its seems like api project is not started and refuse the connection and getting similar error while accessing the api controller.
I'm writing a Windows service. It periodically connects to a SQL database and looks for new records. I can read the SQL database without an issue and it gets the data using a SqlDataReader. I then have a while loop that just does a while Read. Part way through the while loop I create a web request to send that data to a server side component. For that I am using RestSharp v107. When I call ExecuteAsync with the request, I can see the data being sent and it ends up on my server side without an issue. However, when the response comes back, it has wiped out my SqlDataReader so on the next loop I get "Exception: Invalid attempt to call Read when reader is closed." as the reader is null. Here is the code, truncated where necessary for brevity.
private async Task AddUpdateCustomers(SqlConnection poConn)
{
string sQuery = "select * from customers";
try
{
SqlCommand oCmd = new SqlCommand(sQuery, poConn);
poConn.Open();
using (SqlDataReader dataReader = oCmd.ExecuteReader())
{
if (dataReader.HasRows)
{
while (dataReader.Read())
{
int iRecordId = dataReader.GetInt32(dataReader.GetOrdinal("ID"));
Customer customer = new Customer()
{
CustomerId = dataReader.GetString(dataReader.GetOrdinal("CustomerCodeFinancialReference")),
Name = dataReader.GetString(dataReader.GetOrdinal("Name"))
// more fields here removed for brevity
};
RestRequest request = new RestRequest();
request.AddHeader("Profile", aCLIntacctClientServiceConfiguration.ProfileName);
request.AddHeader("Entity", aCLIntacctClientServiceConfiguration.EntityName);
request.AddHeader("CreateUpdate", dataReader.GetBoolean(dataReader.GetOrdinal("IsNew")) ? "create" : "update");
request.AddHeader("Type", "Customer");
request.AddHeader("CorrelationId", Guid.NewGuid().ToString());
string body = ObjectToString(customer);
request.AddStringBody(body, DataFormat.Json);
var options = new RestClientOptions(ClientURI)
{
ThrowOnAnyError = false,
Timeout = 30000
};
RestClient client = new RestClient(options);
RestResponse response = await client.ExecuteAsync(request);
if (!string.IsNullOrEmpty(response.Content))
{
try
{
CustomResponse customerResponseObject = JsonConvert.DeserializeObject<CustomResponse>(response.Content);
if (customerResponseObject.ExitCode == 0)
{
WriteBackToStagingTable(iRecordId, true, "");
}
else
{
string sMessages = "";
foreach (CustomResponseMessage message in customerResponseObject.Messages)
{
sMessages += $"Record ID '{message.RecordId}' failed with the following error: '{message.MessageValue}'" + Environment.NewLine;
}
WriteBackToStagingTable(iRecordId, false, sMessages);
}
}
catch (Exception ex)
{
WriteBackToStagingTable(iRecordId, false, ex.Message + Environment.NewLine + response.Content);
}
}
}
if (!dataReader.IsClosed)
{
dataReader.Close();
}
}
else
{
// No records read from db
}
}
}
catch (Exception ex)
{
HandleLogRequest("Exception: " + ex.Message);
}
}
I've tried using PostAsync but that didn't work and reading the documentation, it isn't what I want. I cannot see why after calling client.ExecuteAsync the dataReader is suddenly null. I'm using RestSharp v107 and so many examples on the web but they are earlier versions and there are a lot of differences.
Rather than pass the connection round as it wasn't particularly necessary, I moved the connection into each function and created it as necessary. With the SQL data reader, I didn't bother with the using block. I also changed it so that it was executing asynchronously.
SqlDataReader dataReader = await oCmd.ExecuteReaderAsync();
Once I'd done that, calling the rest client execute method, it returned and the data reader was still in scope.
I'm trying to write an infinite length response body and detect when a client disconnects so I can stop writing. I'm used to getting socket exceptions or similar when a client closes the connection but that doesn't seem to be happening when writing directly to Response.Body. I can close the client applications and the server side just keeps on writing. I've included the relevant code below. It's entirely possible there is a better way to do it but this came to mind. Basically I have a live video feed which should go on forever. I'm writing to ResponseBody as chunked content (No content length, flushing after each video frame). The video frames are received via an event callback from elsewhere in the program so I'm subscribing to the events in the controller method and then forcing it to stay open with the await Task.Delay loop so the Response stream isn't closed. The callback for H264PacketReceived is formatting the data as a streaming mp4 file and writing it to the Response Stream. This all seems to work fine, I can play the live stream with ffmpeg or chrome, but when I close the client application I don't get an exception or anything. It just keeps writing to the stream without any errors.
public class LiveController : ControllerBase
{
[HttpGet]
[Route("/live/{cameraId}/{stream}.mp4")]
public async Task GetLiveMP4(Guid cameraId, int stream)
{
try
{
Response.StatusCode = 200;
Response.ContentType = "video/mp4";
Response.Headers.Add("Cache-Control", "no-store");
Response.Headers.Add("Connection", "close");
ms = Response.Body;
lock (TCPVideoReceiver.CameraStreams)
{
TCPVideoReceiver.CameraStreams.TryGetValue(cameraId, out cameraStream);
}
if (this.PacketStream == null)
{
throw new KeyNotFoundException($"Stream {cameraId}_{stream} not found");
}
else
{
connected = true;
this.PacketStream.H264PacketReceived += DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed += PacketStream_StreamClosed;
}
while(connected)
{
await Task.Delay(1000);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
connected = false;
this.PacketStream.H264PacketReceived -= DefaultStream_H264PacketReceived;
this.PacketStream.StreamClosed -= PacketStream_StreamClosed;
}
}
private bool connected = false;
private PacketStream PacketStream;
private Mp4File mp4File;
private Stream ms;
private async void PacketStream_StreamClosed(PacketStream source)
{
await Task.Run(() =>
{
try
{
Console.WriteLine($"Closing live stream");
connected = false;
ms.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
private async void DefaultStream_H264PacketReceived(PacketStream source, H264Packet packet)
{
try
{
if (mp4File == null && packet.IsIFrame)
{
mp4File = new Mp4File(null, packet.sps, packet.pps);
var _p = mp4File.WriteHeader(0);
await ms.WriteAsync(mp4File.buffer, 0, _p);
}
if (mp4File != null)
{
var _p = mp4File.WriteFrame(packet, 0);
var start = mp4File._moofScratchIndex - _p;
if (_p > 0)
{
await ms.WriteAsync(mp4File._moofScratch, start, _p);
await ms.FlushAsync();
}
}
return;
}
catch (Exception ex)
{
connected = false;
Console.WriteLine(ex.ToString());
}
}
Answering my own question.
When the client disconnects mvc core sets the cancellation token HttpContext.RequestAborted
By monitoring and/or using that cancellation token you can detect a disconnect and clean everything up.
That said, the entire design can be improved by creating a custom stream which encapsulates the event handling (producer/consumer). Then the controller action can be reduced to.
return File(new MyCustomStream(cameraId, stream), "video/mp4");
The File Method already monitors the cancellation token and everything works as you'd expect.
I'm trying to test the AutomaticRecoveryEnabled property of the RabbitMQ ConnectionFactory. I'm connecting to a RabbitMQ instance on a local VM and on the client I'm publishing messages in a loop. The problem is if I intentionally break the connection, the client just waits forever and doesn't time out. How do I set the time out value? RequestedConnectionTimeout doesn't appear to have any effect.
I'm using the RabbitMQ client 3.5.4
Rudimentary publish loop:
// Client is a wrapper around the RabbitMQ client
for (var i = 0; i < 1000; ++i)
{
// Publish sequentially numbered messages
client.Publish("routingkey", GetContent(i)));
Thread.Sleep(100);
}
The Publish method inside the wrapper:
public bool Publish(string routingKey, byte[] body)
{
try
{
using (var channel = _connection.CreateModel())
{
var basicProps = new BasicProperties
{
Persistent = true,
};
channel.ExchangeDeclare(_exchange, _exchangeType);
channel.BasicPublish(_exchange, routingKey, basicProps, body);
return true;
}
}
catch (Exception e)
{
_logger.Log(e);
}
return false;
}
The connection and connection factory:
_connectionFactory = new ConnectionFactory
{
UserName = _userName,
Password = _password,
HostName = _hostName,
Port = _port,
Protocol = Protocols.DefaultProtocol,
VirtualHost = _virtualHost,
// Doesn't seem to have any effect on broken connections
RequestedConnectionTimeout = 2000,
// The behaviour appears to be the same with or without these included
// AutomaticRecoveryEnabled = true,
// NetworkRecoveryInterval = TimeSpan.FromSeconds(10),
};
_connection = _connectionFactory.CreateConnection();
It appears this is a bug in version 3.5.4. Version 3.6.3 does not wait indefinitely.
I'm trying to write a generic host process (WinForm) which host different WCF Service implementation of the same contract.
When I run the first one it works OK, but when I launch the other one (in parallel) with a different address is throws that I use the same address twice (addr and port) -> path is different though..
private bool InitializeServiceHost()
{
bool isInitialized = true;
try
{
Log.InfoFormat("Loading service DLL {0} and class {1}", _dllPath, _serviceClassName);
var asm = Assembly.LoadFile(_dllPath);
_service = (IGfnService) asm.CreateInstance(_serviceClassName);
if (_service == null)
throw new ApplicationException(string.Format("Could not instansiate {0} from DLL {1}", _serviceClassName, _dllPath));
_service.Init(_myGuidStr);
Uri uri = new Uri("net.tcp://localhost:9085/GfnService/" + _myGuidStr);
var host = new ServiceHost(_service, uri);
Log.InfoFormat("About to open host, State: {0}, URI: {1} ", host.State, uri);
host.Open();
_serviceUri = uri.ToString();
Log.InfoFormat("Gfn service started successfully, State: {0}, URI: {1} ", host.State, uri);
}
catch (Exception ex)
{
Log.Error(ex.Message, ex);
isInitialized = false;
Application.Exit();
}
return isInitialized;
}
Any help will be appreciated....
Got it! it works now! (thanks to all commenters)
var host = new ServiceHost(_service);
Log.Info("Service host generated.");
ServiceEndpoint serviceEndpoint = host.Description.Endpoints.Find(typeof(IGfnService));
if (serviceEndpoint == null)
{
serviceEndpoint = host.AddServiceEndpoint(typeof(IGfnService), new NetTcpBinding
{
MaxConnections = 10,
PortSharingEnabled = true
}, uri);
Log.InfoFormat("Endpoint [{0}] added", serviceEndpoint);
}
The trick was to add the PortSharingEnabled! so the two instances can share the same port! (I should have though about it before, but at least I got a chance to share!)
Thanks!