I am having problems using fulfilling HEAD requests in NancyFX (0.23.2). I am using Nancy self-hosting and GET works fine, but HEAD just causes a dropped connection. From debugging the source, it seems that an exception is being thrown at NancyHost.OutputWithDefaultTransferEncoding (line 321), with additional information "An operation was attempted on a non-existent network connection"
Do I need to do anything special to support HEAD?
Thanks,
Jon
public class Program
{
static void Main(string[] args)
{
var hostConfiguration = new HostConfiguration();
hostConfiguration.UrlReservations.CreateAutomatically = true;
var _host = new NancyHost(hostConfiguration, new Uri("http://localhost:1010"));
_host.Start();
Console.ReadKey();
}
}
public class Module : NancyModule
{
public Module()
{
Get["/"] = x =>
{
return 201;
};
}
}
Related
I have a .net core backend with SignalR and a react frontend. I have a basic hub set up with ConcurrentDictionary to manage connection ids:
namespace backend.Hubs
{
public class OrderHub : Hub, IOrderHub
{
private readonly IHubContext<OrderHub> hubContext;
public static ConcurrentDictionary<string, List<string>> ConnectedUsers = new ConcurrentDictionary<string, List<string>>();
public OrderHub(IHubContext<OrderHub> hubContext)
{
this.hubContext = hubContext;
}
public async Task SendMessage(OrderResponseDto order, string id)
{
List<string> connectedUser = null;
ConnectedUsers.TryGetValue(id, out connectedUser);
await hubContext.Clients.Clients(connectedUser).SendAsync("neworder",order);
}
public void AddMapping(string id)
{
List<string> existingUserConnectionIds;
ConnectedUsers.TryGetValue(id, out existingUserConnectionIds);
if (existingUserConnectionIds == null)
{
existingUserConnectionIds = new List<string>();
}
existingUserConnectionIds.Add(Context.ConnectionId);
ConnectedUsers.TryAdd(id, existingUserConnectionIds);
}
public override Task OnDisconnectedAsync(Exception e)
{
List<string> existingUserConnectionIds = null;
foreach(var val in ConnectedUsers.Values)
{
if (val.Contains(Context.ConnectionId))
{
existingUserConnectionIds = val;
break;
}
}
if (existingUserConnectionIds != null)
{
existingUserConnectionIds.Remove(Context.ConnectionId);
}
var keys = ConnectedUsers.Where(en => en.Value.Count == 0).Select(k => k.Key);
foreach(var key in keys)
{
List<string> garb = null;
ConnectedUsers.TryRemove(key, out garb);
}
return base.OnDisconnectedAsync(e);
}
}
}
On the frontend, I establish the connection and call the AddMapping method to save the client connection id to the concurrent dictionary. All works fine when no throttling is enabled in the developer console in the frontend. However, if I change the throttling to slow or fast 3g I encounter a weird problem. The connection is established as usual and I invoke the method. From debugging in .net core I see that the method is called on the backend however the value isn't saved in the concurrent dictionary and it doesn't return anything. The react client thinks the connection is lost and reconnects. Specifically, I am getting the following errors:
This error only happens when I try to invoke a hub method from the client on throttled connection. On an unthrottled connection, it works fine.
Additional client code :
const newConnection = new HubConnectionBuilder()
.withUrl(env.realtimeBaseUrl+'orderhub', {
// skipNegotiation: true,
// transport: HttpTransportType.WebSockets
})
.withAutomaticReconnect()
.build();
newConnection.start().then(r => {
fetchOrders()
setConnectionStatus(connectingForFirstTime);
newConnection.invoke("AddMapping",business.id.toString()).then(res=>{
console.log(res)
setConnection(newConnection);
setConnectionStatus(connected)
})
newConnection.on("neworder",(order)=>{
// data handling
})
newConnection.onreconnecting(()=>setConnectionStatus(reconnecting))
newConnection.onreconnected(()=>{
newConnection.invoke("AddMapping",business.id.toString()).then(res=>{
console.log(res)
setConnection(newConnection);
setConnectionStatus(connected)
})
});
newConnection.onclose(()=>setConnection(null));
}).catch(err => setConnectionStatus(off));
I just tried it on one of my sites and it seems like the way the dev tools performs the throttling disrupts websocket connections to the point that it doesn't seem to work bi-directionally whether it is on slow3g or fast3g simulation. I can reproduce your error on my otherwise working site. My suspicion is the simulator, not your code.
What is the problem: System.TimeoutException: 'The request channel timed out while waiting for a reply after 00:00:59.977913. So, basically it can be everything.
What do I have:
I create a simple solution to found a fix. What really make me confused is that console app works just fine, however wpf app with same configuration does not work. Solution include four projects(code made for debugging purpose, please don't judge it):
library with contracts and their implementation.
public class DeviceService : IDeviceService
{
public string GetDevices()
{
return "hello world";
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
library with host.
public class DeviceServiceHostFactory
{
ServiceHost host;
public DeviceServiceHostFactory()
{
ServiceMetadataBehavior metadataBehavior;
BasicHttpBinding binding = new BasicHttpBinding();
Uri address = new Uri("http://localhost:4000/");
host = new ServiceHost(typeof(DeviceService), address);
Type contract = typeof(IDeviceService);
host.AddServiceEndpoint(contract, binding, "");
}
public void Start()
{
host.Open();
}
public void Stop()
{
host.Close();
}
}
desktop app that start service and consume it (does not work)
public partial class MainWindow : Window
{
private DeviceServiceHostFactory _deviceService;
public MainWindow()
{
InitializeComponent();
try
{
_deviceService = new DeviceServiceHostFactory();
_deviceService.Start();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
private void Btn_custom_Click(object sender, RoutedEventArgs e)
{
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
txt_custom.Text = channel.GetDevices();
Console.WriteLine();
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
console app (works fine)
class Program
{
static void Main(string[] args)
{
DeviceServiceHostFactory _deviceService = new
DeviceServiceHostFactory();
try
{
_deviceService.Start();
BasicHttpBinding binding = new BasicHttpBinding();
EndpointAddress endpoint =
new EndpointAddress("http://localhost:4000/");
var factory =
new ChannelFactory<IDeviceService>(
binding, endpoint);
var channel = factory.CreateChannel();
Console.WriteLine(channel.GetDevices());
Console.ReadLine();
}
catch (Exception ex)
{
_deviceService.Stop();
Console.WriteLine(ex.StackTrace);
}
}
}
[ServiceContract]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
I really spend a lot of time for this, and I will be very grateful for every solution or thought how can I debug it more advanced.
Hosting wcf service in application with UI is little bit tricky, so I hope this will help someone.
Took it from book Learning WCF: A hands-On Guide By Michele Leroux Bustamante, Chapter 4, so fo more information please find this book.
To host service in Windows application or WPF application, we have to create a new thread to start it in a new synchronization context. It can be done in two ways:
First, is to create service host before the UI thread created. Here service executes in a new synchronization contenxt before application starts.
static class Program
{
static void Main()
{
DeviceServiceHostFactory deviceService = new DeviceServiceHostFactory();
deviceService.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow);
}
}
Second, is to initialize service host on a separate thread, after UI been created
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Thread thread;
thread = new Thread(ServiceInitialize);
thread.IsBackground = true;
thread.Start();
}
private void ServiceInitialize()
{
var service = new DeviceServiceHostFactory();
service.Start();
}
}
This means the messages are processed on threads form the thread pool instead of through the message loop.
First, we should give the current account permissions when we occupy the Operation system ports to host services.
This function could be accomplished by the below command.
Netsh http add urlacl url=https://+:80/MyUri user=DOMAIN\user
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
If we don’t want to do this, we could directly run the service with administrator accounts.
Thereby I suspect there is something wrong with the process of hosting the service. Have you tried running the WPF application with an administrator account?
Besides, I suggest you add a namespace in the service contract.
[ServiceContract(Namespace ="MyNamespace")]
public interface IDeviceService
{
[OperationContract]
string GetDevices();
}
Sometimes, it could run into problems when the service contract doesn’t have a namespace property.
Feel free to let me know if the problem still exists.
We have just upgraded our SyncGatewaty to 2.1. So now I’m refactoring our client code to use CouchbaseLite 2.1. When I try to replicate I get the error:
Got LiteCore error: Not Found (6/404)
I originally got the error when connecting to our Dev Server, and then installed a local clean copy on my laptop and I get the same error when trying to connect to it too.
Log:
INFO) Couchbase 2019-01-10T10:56:47.8503147-07:00 (Startup) [1] CouchbaseLite/2.1.2 (.NET; Microsoft Windows 10.0.17763 ) Build/13 LiteCore/ (15) Commit/9aebf28
WARNING) LiteCore 2019-01-10T10:56:48.1943139-07:00 {C4SocketImpl#1}==> class litecore::repl::C4SocketImpl ws://localhost.com:443//_blipsync
WARNING) LiteCore 2019-01-10T10:56:48.1943139-07:00 {C4SocketImpl#1} Unexpected or unclean socket disconnect! (reason=WebSocket status, code=404)
ERROR) Sync 2019-01-10T10:56:48.1993137-07:00 {Repl#2}==> class litecore::repl::Replicator c:\temp\content_meta_data.cblite2\ ->ws://localhost:443//_blipsync
ERROR) Sync 2019-01-10T10:56:48.1993137-0
7:00 {Repl#2} Got LiteCore error: Not Found (6/404)
My code:
using System;
using System.IO;
using Couchbase.Lite;
using Couchbase.Lite.Support;
using Couchbase.Lite.Sync;
using NLog;
namespace ReplicatorExample
{
public class DatabaseManager
{
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
public const string BUCKET_CONTENT_META_DATA = "content_meta_data";
private static DatabaseManager _instance;
public static DatabaseManager GetInstance()
{
NetDesktop.Activate();
NetDesktop.EnableTextLogging("logs");
return _instance ?? (_instance = new DatabaseManager());
}
public void InitializeBuckets()
{
try
{
var defaultAuthenticator = GetDefaultAuthenticator();
var dirInfo = new DirectoryInfo($"c:\\temp\\{BUCKET_CONTENT_META_DATA}");
if (!dirInfo.Parent.Exists)
{
dirInfo.Parent.Create();
}
var database = new Database(dirInfo.FullName);
// Create replicator to push and pull changes to and from the cloud
var targetEndpoint = new URLEndpoint(new Uri("ws://localhost:4985"));
var replConfig = new ReplicatorConfiguration(database, targetEndpoint)
{
Authenticator = defaultAuthenticator,
Continuous = true,
//Channels = new List<string>
//{
// "approved",
//
//}
};
var replicator = new Replicator(replConfig);
replicator.AddChangeListener((sender, args) =>
{
if (args.Status.Error != null)
{
_log.Error($"{args.Status.Error}");
}
else
{
_log.Debug(args.Status);
}
});
replicator.Start();
}
catch (Exception e)
{
_log.Error(e);
}
}
private Authenticator GetDefaultAuthenticator()
{
return new BasicAuthenticator("BigD","123456");
}
}
}
I believe you need to specify the database name in the URL for targetEndpoint.
E.g: var targetEndpoint = new URLEndpoint(new Uri("ws://localhost:4984/mydatabase"));
I'm working on a project that computes a continuous flow of data.
I've been strugling lately with some memory and networking exceptions to the point where I ask myself if the way i'm getting the data from my database is good.
I am using:
.NET 4.6.1
Akka.NET 1.0.8
RavenDB.Client 3.5.1
Here's an example of how I load data into my actors:
public class MyActor : ReceiveActor
{
public MyActor (ImmutableRegistration registration)
{
Receives();
Self.Tell(new InitDBCache());
}
private void Receives()
{
Receive<InitDBCache>(t =>
{
var builder = new DataBaseCacheBuilder();
builder.BuildFor(registration).ContinueWith(result =>
{
return new DBCacheReceived(result.Result);
},
TaskContinuationOptions.AttachedToParent &
TaskContinuationOptions.ExecuteSynchronously).PipeTo(Self);
});
Receive<DBCacheReceived>(msg =>
{
// Init actor with retrieved data
});
}
private sealed class InitDBCache
{
public InitDBCache() { }
}
private sealed class DBCacheReceived
{
public DBCacheReceived(DataBaseCache cache)
{
this.Cache = cache;
}
public DataBaseCache Cache { get; }
}
}
The DataBaseCacheBuilder goes like this :
public sealed class DataBaseCacheBuilder
{
public DataBaseCacheBuilder()
{
}
public async Task<DataBaseCache> BuildFor(ImmutableRegistration registration)
{
// I have a repository pattern on top of the ravendb client
using (var session = OutsideRefs.DataStore.OpenRavenDbSession())
{
var queryResult1 = await session.repository1.executeQueryAsync(registration.Id);
var queryResult2 = await session.repository2.executeQueryAsync(registration.Id);
return new DataBaseCache(queryResult1, queryResult2);
}
}
}
Concretely, my program throws a fair number of
"System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host."
Those exceptions are throwed by the ravendb client.
Does anyone see a problem or a correlation with my code and the exception ?
Does using async/await to regroup async calls a bad thing to do even though I'm piping the result ?
We are running a Silverlight application running on IIS 7.5 using Forms authentication to sign in users. We have a RIA service which is protected using RequiresAuthentication, and an ErrorHandlingService and a LoggingService which is not.
Recently we seem to be spammed with requests to our ErrorHandlingService - in the order of 50 pr. second - producing the following output in the IIS log:
2013-10-01 11:19:12 xxx.xxx.xxx.xxx POST
...ErrorService.svc
- 80 - xxx.xxx.xxx.xxx Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+Trident/4.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0;+.NET4.0C;+.NET4.0E;+InfoPath.2;+MS-RTC+LM+8)
403 6 5 15
Now a little more detail on the setup:
The ErrorHandlingService has a single method accepting an Exception wrapper class, which will log the exception info into a table in the database, and the LoggingService accepts a LogMessage and same exception wrapper and logs the message to a file using NLog.
Whenever an exception occurs on the protected service, the silverlight client will first call the ErrorHandlingService to record the exception, and afterwards the LoggingService to log it to file.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ErrorHandlingService : IErrorHandlingService
{
public string RecordError(ExceptionTransport error)
{
if (error == null)
{
return null;
}
var hex = HandMadeException.CreateFrom(error);
var res = DiagnosticsHandler.DefaultInstance.HandleException(hex);
var fb = res.GetFeedBack(DatabaseSink.FeedBackEntryId);
var dbId = "";
if (fb != null)
{
dbId = fb.ToString();
}
return dbId;
}
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class LoggingService : ILoggingService
{
private static NLog.Logger _logger = NLog.LogManager.GetLogger("Trace");
public void LogError(LogMessage message, ExceptionTransport error)
{
string log = message.Message;
if (error != null)
{
log = string.Format("{0}: {1}", log, error.ToString());
}
switch (message.Level)
{
case LogLevel.Trace:
_logger.Trace(log);
break;
case LogLevel.Debug:
_logger.Debug(log);
break;
case LogLevel.Info:
_logger.Info(log);
break;
case LogLevel.Warning:
_logger.Warn(log);
break;
case LogLevel.Error:
_logger.Error(log);
break;
case LogLevel.Fatal:
_logger.Fatal(log);
break;
}
}
}
public class ErrorHandlingService : ErrorService, IErrorHandler
{
private LogHandlingService _loggingService = new LogHandlingService();
public ErrorHandlingService()
: base(WcfWebUtility.CreateFactory<IErrorHandlingService>("xxxxErrorHandlingService"))
{
}
public bool HandleError(Exception error)
{
base.RecordError(error, OnErrorRecorded, false);
}
private void LogError(Exception error, string errorId, bool showUserMessage)
{
_loggingService.Log(string.Format("Error '{0}' occured on Ecofleet v. '{1}' for user '{2}'", errorId, ProductVersion.GetEcofleetVersion(), AutologUser.Current), Autolog.DiagnosticsService.Logging.LogLevel.Error, error);
}
private void OnErrorRecorded(ErrorResult result)
{
bool showUserMessage = false;
if (result.UserState is bool)
{
showUserMessage = (bool)result.UserState;
}
LogError(result.ErrorRecorded, result.ErrorId, showUserMessage);
}
... Shortened for brevity
}
So this is what's happening:
In the IIS log output we see a ton of requests to the
ErrorHandlingService, but none to the LoggingService.
Nothing is entered into the database suggesting that the error parameter is
null.
The application works fine, and no users are complaining about
errors. I would expect any user getting 55 errors pr. second to
either contact the support department, or at the very least log
off...
The client IP address seems to remain the same most of the
time.
So is it possibly an (malicious) attack? Or could it be a client version discrepancy (if a new version is deployed and a client doesn't download it, would it be running an old client version against a new server?)? Or something else ... ?