I'm afraid this an XY problem but I cannot find a solution by myself.
To narrow down the problem I create a new C# project with an empty form. Here the program.cs code (updated from the original question to have a very minimal example):
public partial class Form1 : Form
{
private IDisposable webApp;
const string url = "http://localhost:8080";
public Form1()
{
InitializeComponent();
Debug.WriteLine("before");
foo();
webApp = WebApp.Start<Startup>(url);
Debug.WriteLine("after");
foo();
}
private void foo()
{
Debug.WriteLine("foo");
}
}
class Startup
{
public void Configuration(IAppBuilder app) { }
}
Here the (weird) output:
before
foo
after
after
after
foo
foo
foo
Removing the WebApp.Start call leads to the expected output:
before
foo
after
foo
Why?
This is happening because internally Debug.Writeline uses a Trace Listener. If you inspect the Trace.Listeners collection before and after the WebApp.Start line, you'll notice that the web app is adding a second trace listener. So your log messages are getting executed once, but are writing to the "log" multiple times, because there are extra listeners.
The application started with a single DefaultTraceListener, then the web app starts a TextWriterTraceListener. You can remove the extra listener by adding this to your configuration:
Trace.Listeners.Remove("HostingTraceListener");
A second option to fix this is to implement your own ITraceOutputFactory:
public class MyFactory: ITraceOutputFactory
{
public TextWriter Create(string outFile)
{
return TextWriter.Null;
}
}
And register it with your web app:
var myFactory = new MyFactory();
var provider = ServicesFactory.Create(fact => fact.AddInstance<ITraceOutputFactory>(myFactory));
WebApp.Start<Startup>(provider, new StartOptions(url)))
Related
I am injecting two services into my dot net core web api, the main service relies on data in the helper service. The helper service populates this data in the constructor, however when the main service goes to use this data it is not ready because the constructor of the helper service has not finished by the time it is needed.
I thought DI and the compiler would resolve and chain these services properly so the helper service would not be used until it was fully instantiated.
How I tell the main service to wait until the helper service is fully resolved and instantiated?
Generic sample code of what I am doing. I call the DoSomething() in MainSerice the HelperService calls out to an external API to get some data, that data is needed in the MainService.
StartUp.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHelperService, HelperService);
services.Scoped<IMainService, MainService);
}
MainService.cs
public class MainService : IMainService
{
private readonly IHelperServuce _helper;
public MainService(IHelperService HelperService)
{
_helper = HelperService;
}
public void DoSomething()
{
string helperParameter = _helper.Param1; //This fails because the constructor of HelperService has not finished
}
}
HelperService.cs
public class HelperService : IHelperService
{
public HelperService()
{
GetParamData();
}
private async void GetParamData()
{
var response = await CallExternalAPIForParameters(); //This may take a second.
Params1 = response.value;
}
private string _param1;
public string Param1
{
get
{
return _param1;
}
private set
{
_param1 = value;
}
}
}
You are not awaiting the async method GetParamData() data in the constructor. That is, ofcourse, not possible. Your constructor should only initialize simple data. You could fix this by, instead of using a property to return, you could also return a Task from a method called (for example) Task<string> GetParam1(). Which could cache the string value.
for example:
public class HelperService : IHelperService
{
private string _param1;
// note: this is not threadsafe.
public async Task<string> GetParam1()
{
if(_param1 != null)
return _param1;
var response = await CallExternalAPIForParameters(); //This may take a second.
_params1 = response.value;
return _param1;
}
}
You could even return a ValueTask<string> because most of the calls can be executed synchronously.
Pass a lambda to the helper service that initializes the variable in your main service, as in...
Helper service.getfirstparam( (response) ->
{ firstparam = response.data;});
While (firstparam == null)
sleep
// now do your processing
I have an ASP.Net Web Forms app where I just integrated Sustainsys.Saml2 library.
I've never used any sort of logging mechanism and I'm trying to figure out how to add or create an ILoggerAdapter for the library stated on their troubleshooting page.
I've decided to use NLog (please feel free to recommend a different one) and either I'm not understanding this well, or am not using the right keyword to search for what I need/want, or their isn't a lot of documentation on it.
Currently, I'm using the HttpModule version of Sustainsys.Saml2. Any other information available upon request.
Any help would be great.
Currently, I'm configuring the Sustainsys.Saml2 library through both web.config and the global.asax files. Here's the class my global.asax calls:
public class Saml2Config {
private static bool _alreadyInitialized;
private static readonly object Lock = new object();
public static void Initialize() {
if (_alreadyInitialized) {
return;
}
lock (Lock) {
if (_alreadyInitialized) {
return;
}
var domain = PageHelper.GetDomainURL(true);
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.EntityId.Id = $"{domain}/federation/Saml2";
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.ModulePath = "/federation/Saml2";
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.ReturnUrl = new Uri($"{domain}/mybarry");
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.PublicOrigin = new Uri($"{domain}");
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.Logger = new NullLoggerAdapter();
_alreadyInitialized = true;
}
}
}
The interface is pretty straightforward
public interface ILoggerAdapter
{
void WriteInformation(string message);
void WriteError(string message, Exception ex);
void WriteVerbose(string message);
}
I would implement it as follows:
public class NLogAdapter : ILoggerAdapter
{
private static Logger Logger = LogManager.GetLogger("Saml2");
public void WriteInformation(string message)
{
Logger.Info(message);
}
public void WriteError(string message, Exception ex)
{
Logger.Error(ex, message);
}
public void WriteVerbose(string message)
{
Logger.Debug(message);
}
}
And finally set it:
Sustainsys.Saml2.Configuration.Options.FromConfiguration.SPOptions.Logger = new NLogAdapter();
The ILoggerAdapter contains methods for different loglevels. Make an adapter class that implements ILoggerAdapter and writes to NLog. Then set SPOptions.Logger to an instance of your adapter class.
If you want an example, you can check out the adapter for Asp.Net Core that logs to the Asp.Net Core logging system and is the default for the Sustainsys.Saml2.AspNetCore2 package: https://github.com/Sustainsys/Saml2/blob/master/Sustainsys.Saml2.AspNetCore2/AspNetCoreLoggerAdapter.cs
For the Sustainsys.Saml2.HttpModule library the default is the NullLoggerAdapter which simply discards any logs. Only reason to use it is to not have to nullcheck the Logger property everywhere it is used (that code was written before the ?. syntax was introduced.)
I have an existing Windows Service that starts up, reads some configs, spins up some threads and does some useful work.
Currently I log that work (through TopShelf.Log4Net / Log4Net) to disk (or console).
I was thinking it would be nice to expose an API to allow people to query the service (and in the future maybe even config it on the fly)
I'm having difficulty figuring out an appropriate way to plumb the two together though. My existing windows service has a bunch of worker threads and it knows the context of what work is being done, stats and progress and things like that.
But in the context of an ApiController actually handling a request I can't see an obvious/easy means of getting at those stats. I tried passing some object references in the Properties of the IAppBuilder in my Startup class, but any time I explicitly do the config myself I seem to lose the default MVC routes that I had.
Anyone have any suggestions on integrating OWIN into/on top of an existing service?
EDIT: Added code:
So I have a very basic TopShelf runner;
HostFactory.Run(x =>
{
x.Service<MyService>(s =>
{
s.ConstructUsing(name => new MyService());
s.WhenStarted(lb => lb.Start());
s.WhenStopped(lb => lb.Stop());
});
x.RunAsLocalSystem();
And within MyService I had a method StartWorkers() that goes off, starts up a bunch of workers, and keeps track of them.
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<Worker> workers { get; set; }
private List<Thread> _threads { get; set; }
public MyService()
{
StartWorkers();
}
Now, I want to be able to query for the status of those workers from API requests, so I was thinking I could do something like;
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<Worker> workers { get; set; }
private List<Thread> _threads { get; set; }
private IDisposable _webServer { get; set; }
public MyService()
{
StartWorkers();
StartWebServer();
}
private void StartWebServer()
{
const string baseAddress = "http://localhost:10281/";
_webServer = WebApp.Start<Startup>(url: baseAddress);
log.DebugFormat("Loaded webserver at address={0}", baseAddress);
}
All of the OWIN code right now is vanilla from the samples.
When I test this code, I can hit the /api/values sample endpoint which is served from the ValuesController, and all is well.
Now where I'm missing a piece of glue is how to access anything useful in my application from my controller. I can do something naive like making the Worker list public static;
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static List<Worker> workers { get; set; }
In which case from my controller I can do something like;
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
// nonsense/test code
return MyService.workers.Select(i => i.ErrorsEncountered.ToString()).ToArray();
}
There must be a better way of access the internals of my application without manipulation visbility.
What I've seen is that I can pass objects into the Properties of the IAppBuilder when using WebApp.Start(). These are visible then from the route configuration, and I see to be able to access them from within my ApiController, e.g.;
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
var someWorker = base.ControllerContext.Configuration.Properties["someWorkerReference"];
The problem I have when I go down that route is that 'WebApp.Start(url: baseAddress);' works and my routes all function, but using the WebApp.Start() method and passing in an Action causes my routes to break
So instead of spending time fixing the routes, I wanted to see if there's an obvious/known/official means of passing "context" into the web server
So this is where having a container is super helpful. If you have something like public class MyService : IStatusProvider {} then you can register both MyService and IStatusProvider to the same instance you. How to use DI container when OwinStartup talks about using OWIN & dependency injection. And you would add the container setup to start of the program, changing s.ConstructUsing(name => new MyService()); to
s.ConstructUsing(name => {
var container = new Container();
// container setup
return container.resolve<MyService>(); // method depends on your container
});
I am using Ninject in a WebForms application. I have NinjectConfiguration modules for different parts of the application.
All bindings are set to 'InRequestScope' binding. However, when running the application each call to Kernel.Get<T>() returns a new instance.
I am using the following code in my Global.asax:
public class Global : NinjectHttpApplication
{
public static IKernel SharedKernel { get; private set; }
protected override Ninject.IKernel CreateKernel()
{
SharedKernel = new StandardKernel();
// I have added these two lines to resolve an exception about IntPtr
SharedKernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
SharedKernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
SharedKernel.Load(new NinjectDataLayerConfiguration());
return SharedKernel;
}
}
My NinjectModule:
public class NinjectDataLayerConfiguration : NinjectModule
{
public override void Load()
{
Bind<EFContext>().ToSelf().InRequestScope();
Bind<IProjectRepository>().To<ProjectRepository>().InRequestScope();
/* other repositories */
}
}
And in Web.Config I've added a HttpModule to make sure that items are disposed at the end of a request:
<add name="OnePerRequestModule" type="Ninject.OnePerRequestModule" />
But when I run the following code:
var ProjectRepository1 = SharedKernel.Get<IProjectRepository>();
var ProjectRepository2 = SharedKernel.Get<IProjectRepository>();
I get two different instances back and this is causing all kind of errors (since I'm using Entity Framework and my ObjectContext should be shared trough the request).
Any pointers on what I'm doing wrong?
Most likely you do not use one of the web extensions. e.g. Ninject.Web (in addition to Ninject.Web.Common) in case of WebForms
Is it possible to use automapper in a console application?
Its Getting Started Page suggests the bootstrapper class be called from Application start up, but there are no further details about a class to add and call from Main().
How do I go about using this in a simple console app?
You can initialize Automapper in the console startup, there's no limitations; the Application_start is the startup place for a web program in .net/iis, ie code that is called only once. Any configuration that you must call at the start of a web project goes in this method.
edit for comment: if you don't want to create your mappings on the fly, but would rather have a place to initialize all your mappings, just create a function called InitializeAutomapper and make the Mapper.Configure<X, Y> calls in here. Then in your Main() method, just call the function. There are lots of ways to handle configuration, but this is the simpler way to handle it.
code sample
class Program
{
static void Main(string[] args)
{
// the app is starting here
InitializeAutomapper();
// we're configured, let's go!
DoStuff();
}
static void InitializeAutomapper()
{
AutoMapper.Mapper.CreateMap<TypeA, TypeB>();
AutoMapper.Mapper.CreateMap<TypeC, TypeD>();
AutoMapper.Mapper.CreateMap<TypeE, TypeF>();
}
}
I know that this is an old question, but if you found this I want to add an update: Automaper does not allow static initialization anymore.
You can check more here
Below, I'm providing a full example of how to use it on a console app. Hope this might be helpful for someone in the future.
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<MyClass, MyClassDTO>();
});
IMapper mapper = config.CreateMapper();
var myClass = new MyClass(){
Id = 10,
Name = "Test"
};
var dst = mapper.Map<MyClass, MyClassDTO>(myClass);
Console.WriteLine(dst.Id);
}
}
class MyClass
{
public int Id {get;set;}
public string Name {get;set;}
}
public class MyClassDTO
{
public int Id {get;set;}
public string Name {get;set;}
}
Do not forget to include using AutoMapper;
Yes, but it appears to have a dependency on System.Web, which must be included too.
(See Mysterious disappearing reference for more details)