I have a OWIN/Katana self-hosted service app.
One of its functions is to service some data over WebAPI.
In this app I have a class called dataManager, which is responsible for retrieving the data, and passing it onto the API controller, which asked for it.
The data is ultimately served to a mobile platform, so it is very important to cache as much as possible for performance.
Is there a way to pre-load my DataManager at the application startup, and have it pre-execute it's linq queries?
The Application class looks like this:
namespace TaskManager
{
using System;
using Microsoft.Owin.Hosting;
public class TaskManagerApplication
{
protected IDisposable WebApplication;
public void Start()
{
WebApplication = WebApp.Start<WebPipeline>("http://*:8080");
}
public void Stop()
{
WebApplication.Dispose();
}
}
}
The Program class looks like this:
namespace TaskManager
{
using Topshelf;
internal class Program
{
private static int Main()
{
var exitCode = HostFactory.Run(host =>
{
host.Service<TaskManagerApplication>(service =>
{
service.ConstructUsing(() => new TaskManagerApplication());
service.WhenStarted(a => a.Start());
service.WhenStopped(a => a.Stop());
});
host.SetDescription("Task Manager");
host.SetDisplayName("Task Manager");
host.SetServiceName("TaskManager");
host.RunAsNetworkService();
});
return (int) exitCode;
}
}
}
And the data retrieval statement contained within DataManager class look like this:
var rawData = from data in new XPQuery<AccountView3.PipelineData>(uow)
where data.Stage.ToLower().Contains("won")
&& data.RevenueStartDate.Value.Year == DateTime.Today.Year
&& data.WeekOfTheYear >= priorWeekCutoff
select data;
What I do is create a public static class in the API library. That's where I modify the HttpConfiguration object. That is also where I define OnStartup() and OnShutdown() methods. I then call these methods in the pipeline class's methods (your WebPipeline class).
For example (in the MyWebApi library, where my controllers and stuff live):
public class Service
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.EnsureInitialized();
}
public static void OnStartup()
{
// add any startup logic here, like caching your data
}
public static void OnShutdown()
{
// add any cleanup logic here
}
}
Then in the pipeline class:
public class WebPipeline
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
MyWebApi.Service.Register(config);
MyWebApi.Service.OnStartup();
app.UseWebApi(config);
}
public static void Shutdown()
{
MyWebApi.Service.OnShutdown();
}
}
Now your TaskManagerApplication.Start() will result in the API OnStartup() being called. Then you just have to add a call to WebPipeline.Shutdown() in your TaskManagerApplication.Stop() method.
Related
On an Net.Core 6 project I have the IEndpoint extension
public interface IEndpoint {
void Map(IEndpointRouteBuilder builder);
}
And an implementation example:
public class CountryEndpoint : IEndpoint {
public void Map(IEndpointRouteBuilder builder) {
builder.MapGet("countries", async ([FromServices] IService service) => {
List<Country> countries = await service.GetCountries();
return Results.Ok(countries);
})
.WithName("Countries");
.WithApiVersionSet(versionSet)
.MapToApiVersion( 1.0 );
}
}
I configure the endpoints on my application using:
builder.Services.AddEndpoints(typeof(Program));
WebApplication application = builder.Build();
application.MapEndpoints();
Where AddEndpoints and MapEndpoints extensions are:
public static IServiceCollection AddEndpoints(this IServiceCollection services, params Type[] types) {
services
.Scan(x => x.FromAssembliesOf(types).AddClasses(y => y.AssignableTo(typeof(IEndpoint))).AsImplementedInterfaces().WithScopedLifetime());
return services;
}
public static class ApplicationBuilderExtensions {
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder builder) {
using (IServiceScope scope = builder.ServiceProvider.CreateScope()) {
IEnumerable<IEndpoint> endpoints = scope.ServiceProvider.GetServices<IEndpoint>();
foreach (IEndpoint endpoint in endpoints)
endpoint.Map(builder);
}
return builder;
}
}
Question
On CountryEndpoint's Map` method I have:
.WithApiVersionSet(versionSet)
The versionSet variable is created in Program code as follows:
ApiVersionSet versionSet = application.NewApiVersionSet().HasApiVersion(new ApiVersion(1.0)).ReportApiVersions().Build();
How can I create such a variable and use it in Endpoints' Map method?
Usually the versionSet variable and the Map methods are in Program code.
You can create static class with corresponding static field (for example a partial Program class) and use it to store the value and use it in Map:
Top-level statement (Program.cs):
...
ApiVersionSet versionSet = application.NewApiVersionSet().HasApiVersion(new ApiVersion(1.0)).ReportApiVersions().Build();
VersionSet = versionSet;
application.MapEndpoints(); // use Program.VersionSet in IEndpoint.Map implementation
...
// end of top-level statement
static partial class Program
{
internal static ApiVersionSet VersionSet {get;set;}
}
But I would argue that making ApiVersionSet a parameter of IEndpoint.Map and ApplicationBuilderExtensions.MapEndpoints would be a much better approach:
public interface IEndpoint {
void Map(IEndpointRouteBuilder builder, ApiVersionSet versionSet);
}
public static class ApplicationBuilderExtensions {
public static IEndpointRouteBuilder MapEndpoints(this IEndpointRouteBuilder builder, ApiVersionSet versionSet) {
using (IServiceScope scope = builder.ServiceProvider.CreateScope()) {
IEnumerable<IEndpoint> endpoints = scope.ServiceProvider.GetServices<IEndpoint>();
foreach (IEndpoint endpoint in endpoints)
endpoint.Map(builder, versionSet); // pass it here
}
return builder;
}
}
And in top-level statement:
ApiVersionSet versionSet = ...;
application.MapEndpoints(versionSet);
I am trying to run a method on my controller class when my topshelf service starts and I am now finding how to do it. I search and I couldn't find an answer. Can I call a method of my controller class on service startup directly or I do have to do an HttpClient and call an url on localhost?
Code:
Program.cs:
HostFactory.Run(x =>
{
x.Service<OwinService>(s =>
{
s.ConstructUsing(() => new OwinService());
s.WhenStarted(service => service.Start());
s.WhenStopped(service => service.Stop());
});
x.RunAsLocalSystem();
x.StartAutomatically();
x.SetServiceName("Test Service");
x.SetDisplayName("Test Service");
x.SetDescription("Service that Imports / Exports to DB information");
x.EnableServiceRecovery(recoveryOption =>
{
recoveryOption.RestartService(0);
});
});
OwinService.cs:
public class OwinService
{
private IDisposable _webApp;
public void Start()
{
//_timer.Start();
_webApp = WebApp.Start<ApiConfiguration>("http://+:9000");
}
public void Stop()
{
//_timer.Stop();
_webApp.Dispose();
}
}
OutputController.cs
public class OutputController : ApiController
{
public void DoSomething() {};
}
I want to call the DoSomething() on startup.
Find the full sample app demonstrating this problem here.
I'm trying to use OWIN middleware to populate a static identifier that will be accessible by a WebForms page, but I'm noticing that with certain types this does not behave intuitively - specifically AsyncLocal<T>.
Consider the following working sample, using an int:
Simple static container
public static class Container
{
public static int CallId { get; set; }
}
Simple OWIN configuration
[assembly: OwinStartup(typeof(Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use((context, next) =>
{
Container.CallId = 5;
return next.Invoke();
});
}
}
Simple Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (Container.CallId != 5)
{
throw new Exception("What happened to CallId");
}
}
This functions as expected. The middleware sets CallId to 5, the WebForms page sees a 5. The exception is not thrown.
Here's where things break intuition, if I want to use an AsyncLocal<int> for my CallId, the value is no longer available in the WebForms page. E.g.
Broken Container
public static class Container
{
public static AsyncLocal<int> CallId { get; set; }
}
Broken OWIN configuration
[assembly: OwinStartup(typeof(Startup))]
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use((context, next) =>
{
AsyncLocal<int> asyncId = new AsyncLocal<int>();
asyncId.Value = 5
Container.CallId = asyncId;
return next.Invoke();
});
}
}
Broken Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (Container.CallId.Value != 5)
{
throw new Exception("What happened to CallId");
}
}
This does not function as expected. An identifier is created in the middleware, but is not available in the page. The exception is thrown.
Why?
I'm struggling to piece together why this update breaks intuition; I can't think of anything that could be causing the value to disappear.
The process, domain, and thread id all remain unchanged between the middleware component executing and the webform page's On_Load.
Container is static, so only one instance exists in the domain.
The difference in behavior doesn't hinge on primitive vs reference types; I tried this same thing with an simple MyType, CallId doesn't return to null in the WebForm
Where did the static CallId value go?
If you want to see this for yourself, here is a demo github repo.
Here's the commit where things function intuitively.
Here's the commit where things function counter-intuitively.
You are using it wrong. Use the local to hold the desired value.
public static class Container {
private static AsyncLocal<int> current = new AsyncLocal<int>();
public static int CallId {
get {
return current.Value;
}
set {
current.Value = value;
}
}
}
And OWIN configuration remains as it did before.
[assembly: OwinStartup(typeof(Startup))]
public class Startup {
public void Configuration(IAppBuilder app) {
app.Use((context, next) => {
Container.CallId = 5;
return next.Invoke();
});
}
}
the AsyncLocal<T> class will now persist the value across asynchronous flows across threads.
So, there's a bug in some legacy code I'm maintaining. It causes some mild data corruption, so it's rather serious. I've found the root cause, and have made a sample application that reliable reproduces the bug. I would like to fix it with as little impact on existing applications as possible, but I'm struggling.
The bug lies in the data access layer. More specifically, in how an interceptor is injected into a new Nhibernate Session. The interceptor is used to set a specific entity property when saving or flushing. The property, LoggedInPersonID, is found on nearly all our entities. All entities are generated from CodeSmith templates using the database schema, so the LoggedInPersonID property corresponds to a column that is found on nearly all tables in the database. Together with a couple of other columns and triggers, it is used to keep track of which user created and modified a record in the database. Any transaction that inserts or updates data need to supply a LoggedInPersonID value, or else the transaction will fail.
Whenever a client requires a new session, a call is made to OpenSession in the SessionFactory (not Nhibernate's SessionFactory, but a wrapper). The code below shows the relevant parts of the SessionFactory wrapper class:
public class SessionFactory
{
private ISessionFactory sessionFactory;
private SessionFactory()
{
Init();
}
public static SessionFactory Instance
{
get
{
return Nested.SessionFactory;
}
}
private static readonly object _lock = new object();
public ISession OpenSession()
{
lock (_lock)
{
var beforeInitEventArgs = new SessionFactoryOpenSessionEventArgs(null);
if (BeforeInit != null)
{
BeforeInit(this, beforeInitEventArgs);
}
ISession session;
if (beforeInitEventArgs.Interceptor != null
&& beforeInitEventArgs.Interceptor is IInterceptor)
{
session = sessionFactory.OpenSession(beforeInitEventArgs.Interceptor);
}
else
{
session = sessionFactory.OpenSession();
}
return session;
}
}
private void Init()
{
try
{
var configuration = new Configuration().Configure();
OnSessionFactoryConfiguring(configuration);
sessionFactory = configuration.BuildSessionFactory();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
while (ex.InnerException != null)
{
Console.Error.WriteLine(ex.Message);
ex = ex.InnerException;
}
throw;
}
}
private void OnSessionFactoryConfiguring(Configuration configuration)
{
if(SessionFactoryConfiguring != null)
{
SessionFactoryConfiguring(this, new SessionFactoryConfiguringEventArgs(configuration));
}
}
public static event EventHandler<SessionFactoryOpenSessionEventArgs> BeforeInit;
public static event EventHandler<SessionFactoryOpenSessionEventArgs> AfterInit;
public static event EventHandler<SessionFactoryConfiguringEventArgs> SessionFactoryConfiguring;
public class SessionFactoryConfiguringEventArgs : EventArgs
{
public Configuration Configuration { get; private set; }
public SessionFactoryConfiguringEventArgs(Configuration configuration)
{
Configuration = configuration;
}
}
public class SessionFactoryOpenSessionEventArgs : EventArgs
{
private NHibernate.ISession session;
public SessionFactoryOpenSessionEventArgs(NHibernate.ISession session)
{
this.session = session;
}
public NHibernate.ISession Session
{
get
{
return this.session;
}
}
public NHibernate.IInterceptor Interceptor
{
get;
set;
}
}
/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
internal static readonly SessionFactory SessionFactory;
static Nested()
{
try
{
SessionFactory = new SessionFactory();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
throw;
}
}
}
}
The interceptor is injected through the BeforeInit event. Below is the interceptor implementation:
public class LoggedInPersonIDInterceptor : NHibernate.EmptyInterceptor
{
private int? loggedInPersonID
{
get
{
return this.loggedInPersonIDProvider();
}
}
private Func<int?> loggedInPersonIDProvider;
public LoggedInPersonIDInterceptor(Func<int?> loggedInPersonIDProvider)
{
SetProvider(loggedInPersonIDProvider);
}
public void SetProvider(Func<int?> provider)
{
loggedInPersonIDProvider = provider;
}
public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState,
string[] propertyNames, NHibernate.Type.IType[] types)
{
return SetLoggedInPersonID(currentState, propertyNames);
}
public override bool OnSave(object entity, object id, object[] currentState,
string[] propertyNames, NHibernate.Type.IType[] types)
{
return SetLoggedInPersonID(currentState, propertyNames);
}
protected bool SetLoggedInPersonID(object[] currentState, string[] propertyNames)
{
int max = propertyNames.Length;
var lipid = loggedInPersonID;
for (int i = 0; i < max; i++)
{
if (propertyNames[i].ToLower() == "loggedinpersonid" && currentState[i] == null && lipid.HasValue)
{
currentState[i] = lipid;
return true;
}
}
return false;
}
}
Below is a helper class used by applications to register a BeforeInit event handler:
public static class LoggedInPersonIDInterceptorUtil
{
public static LoggedInPersonIDInterceptor Setup(Func<int?> loggedInPersonIDProvider)
{
var loggedInPersonIdInterceptor = new LoggedInPersonIDInterceptor(loggedInPersonIDProvider);
ShipRepDAL.ShipRepDAO.SessionFactory.BeforeInit += (s, args) =>
{
args.Interceptor = loggedInPersonIdInterceptor;
};
return loggedInPersonIdInterceptor;
}
}
}
The bug is especially prominent in our web services (WCF SOAP). The web services endpoint bindings are all basicHttpBinding. A new Nhibernate session is created for each client request. The LoggedInPersonIDInterceptorUtil.Setup method is called after a client is authenticated, with the authenticated client's ID captured in the closure. Then there's a race to reach code that triggers a call to SessionFactory.OpenSession before another client request registers an event handler to the BeforeInit event with a different closure - because, it's the last handler in the BeforeInit event's invocation list that "wins", potentially returning the wrong interceptor. The bug usually happens when two clients are making requests nearly simultaneously, but also when two clients are calling different web service methods with different execution times (one taking longer from authentication to OpenSession than another).
In addition to the data corruption, there's also a memory leak as the event handlers aren't de-registered? It might be the reason why our web service process is recycled at least once a day?
It really looks like the BeforeInit (and AfterInit) events need to go. I could alter the signature of the OpenSession method, and add an IInterceptor parameter. But this would break a lot of code, and I don't want to pass in an interceptor whenever a session is retrieved - I would like this to be transparent. Since the interceptor is a cross cutting concern in all applications using the DAL, would dependency injection be a viable solution? Unity is used in some other areas of our applications.
Any nudge in the right direction would be greatly appreciated :)
Instead of supplying the interceptor at each ISessionFactory.OpenSession call, I would use a single interceptor instance globally configured (Configuration.SetInterceptor()).
This instance would retrieve the data to use from an adequate context allowing to isolate this data per request/user/whatever suits the application.
(System.ServiceModel.OperationContext, System.Web.HttpContext, ..., depending on the application kind.)
The context data in your case would be set where LoggedInPersonIDInterceptorUtil.Setup is currently called.
If you need to use the same interceptor implementation for applications requiring different contextes, then you will need to choose the context to use according to some configuration parameter you would add (or inject it as a dependency in your interceptor).
Dependency Injection example:
DependencyInjectionInterceptor.cs:
using NHibernate;
using System;
using Microsoft.Extensions.DependencyInjection;
namespace MyAmazingApplication
{
public class DependencyInjectionInterceptor : EmptyInterceptor
{
private readonly IServiceProvider _serviceProvider;
public DependencyInjectionInterceptor(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public T GetService<T>() => _serviceProvider.GetService<T>();
public T GetRequiredService<T>() => _serviceProvider.GetRequiredService<T>();
}
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
var cfg = new Configuration();
... // your config setup
cfg.SetListeners(NHibernate.Event.ListenerType.PreInsert, new[] { new AuditEventListener() });
cfg.SetListeners(NHibernate.Event.ListenerType.PreUpdate, new[] { new AuditEventListener() });
services.AddSingleton(cfg);
services.AddSingleton(s => s.GetRequiredService<Configuration>().BuildSessionFactory());
services.AddScoped(s => s.GetRequiredService<ISessionFactory>().WithOptions().Interceptor(new DependencyInjectionInterceptor(s)).OpenSession());
... // you other services setup
}
AuditEventListener.cs:
public class AuditEventListener : IPreUpdateEventListener, IPreInsertEventListener
{
public bool OnPreUpdate(PreUpdateEvent e)
{
var user = ((DependencyInjectionInterceptor)e.Session.Interceptor).GetService<ICurrentUser>();
if (e.Entity is IEntity)
UpdateAuditTrail(user, e.State, e.Persister.PropertyNames, (IEntity)e.Entity, false);
return false;
}
}
So you use interceptor to get your scoped or any other service:
var myService = ((DependencyInjectionInterceptor)e.Session.Interceptor).GetService<IService>();
ICurrentUser in particular is a scoped service which uses HttpContext to get the current user.
I hope it might be helpful for everyone.
I am using Simple Injector for test purpose but pretty new on OOP. I am trying to create loosely couple classes. Here is the my scenario.
I have User repo and interface like this.
public class UserRepository : IUserRepository
{
public void Add(Model.User user)
{
Console.WriteLine("Name:"+user.Name+"\n"+"SurName:"+user.SurName);
}
public void Delete(int id)
{
throw new NotImplementedException();
}
}
public interface IUserRepository
{
void Add(User user);
void Delete(int id);
}
My TestInjectedClass Class and interface are something like this which I am planning to use in Program Main.
public class TestInjectedClass : ITestInjectedClass
{
private readonly IUserRepository _userRepository;
public TestInjectedClass(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public void UserRepoRun()
{
var user = new User() {Id = 1,Name = "ada",SurName = "stack"};
_userRepository.Add(user);
}
}
public interface ITestInjectedClass
{
void UserRepoRun();
}
And My console program looks like this:
class Program
{
static ITestInjectedClass _testInjectedClass;
private static IUserRepository _userRepository;
static void Main(string[] args)
{
_testInjectedClass= new TestInjectedClass(_userRepository);
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
public Program()
{
Bootstrap.Start();
}
}
BootStrap class here:
class Bootstrap
{
public static void Start()
{
var container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
My problem when I run program, I am getting a value exception on the _userRepository inside TestInjectionClass.
How can I properly inject TestInjectionClass and UserRepository to Main Program. Thanks
You need to make Bootstrap.container available in Program.Main and then use it to create instances of classes instead of directly calling their constructors directly:
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
Of course you will need to expose it in Bootstrap for that to work:
class Bootstrap
{
public static Container container;
public static void Start()
{
container = new Container();
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserRepository, TestInjectedClass>(Lifestyle.Singleton);
//container.Register<IUserContext, WinFormsUserContext>();
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
And call Bootstrap.Start from Program.Main:
static void Main(string[] args)
{
Bootstrap.Start();
_testInjectedClass = Bootstrap.container.GetInstance<ITestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
The problem is because you are calling your Bootstrap code in Program class instance constructor.
So, actually when you start your program the execution environment, is calling entry point method Main. And your instance constructor is never executed.
Try changing your entry point method Main and 'Bootstrap' class code:
static void Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container);
_testInjectedClass = container.GetInstance<TestInjectedClass>();
_testInjectedClass.UserRepoRun();
Console.ReadLine();
}
class Bootstrap
{
public static void Start(Container container)
{
// Register your types, for instance:
container.Register<IUserRepository, UserRepository>(Lifestyle.Singleton);
container.Register<ITestInjectedClass, TestInjectedClass>(Lifestyle.Singleton);
container.Register<TestInjectedClass>();
// Optionally verify the container.
container.Verify();
}
}
Please use SimpleInjector
Sample please refer
http://www.c-sharpcorner.com/UploadFile/4d9083/dependency-injection-using-simple-injector/