Caching Does Not Appear to Work in Identity Server 4 - c#

I'm attempting to add caching to our IS4 implementation using their Caching methods. However, my implementation does not appear to be having any impact on the speed of login or the number of queries hitting my database per login (which I would expect caching to reduce both).
The changes I made to implement caching are as follows:
Added the following to Startup.cs ConfigureServices
Updated the services.AddIdenttiyServer() call to include the lines:
.AddInMemoryCaching()
.AddClientStoreCache<IClientStore>()
.AddResourceStoreCache<IResourceStore>()
.AddCorsPolicyCache<ICorsPolicyService>();
Updated ConfigureServices to also have the following:
services.AddScoped<ICorsPolicyService, DefaultCorsPolicyService>();
services.AddScoped<IClientStore, ClientStore>();
services.AddScoped<IResourceStore, ResourceStore>();
That appeared to be the only things I needed to implement, and while the application runs normally, the caching does not seem to be doing anything. What am I missing?

Basically you need to do 2 things:
First implement the IClientStore:
public class ClientStore : IClientStore
{
private readonly IClientService clientService;
public ClientStore(IClientService clientService)
{
this.clientService = clientService;
}
public Task<Client> FindClientByIdAsync(string clientId)
{
var client = this.clientService.GetById(clientId);
return Task.FromResult(client);
}
}
The ClientService is my implementation for getting the client from the db, so there you need to put your own.
Then in the Startup.cs you need:
services.AddIdentityServer(options =>
{
options.Caching.ClientStoreExpiration = new TimeSpan(0, 5, 0);
})
.AddInMemoryCaching()
.AddClientStoreCache<ClientStore>()
.// More stuff that you need
This is for the Client Caching but for the Cors and the ResourceStore is quite the same.
I think that you are missing the options.Caching.ClientStoreExpiration part. Start from there.
Hope that this helps.
PS: Forgot to mention - you don't need to explicitly inject your implementation of the IClientStore. By adding it to the .AddClientStoreCache<ClientStore>() it gets injected. But (as in my example) if you have other services, used by the store, you need to inject them.

There is no standard way to cache users.
It caches only:
Clients - AddClientStoreCache
Resources - AddResourceStoreCache
CorsPolicy - AddCorsPolicyCache
More details you can get from documentations

Related

IdentityServer 4, Create Panel to CRUD Clients

Currently I Have configured Identityserver4 as separated project + My WebAPI and store in DB Credentials in IdentityServer.
Now i have problem how to make CRUD(In my frontend API) to IdentityServer(I want from my API add Clients to IdentityServer)
How to make property?
From IdentityServer4.EntityFramework and IdentityServer4.EntityFramework.Storage, you have access to IConfigurationDbContext (once you've added the required services in ConfigureServices using e.g. AddConfigurationStore). Because this is registered as part of the Dependency Injection system, you can take a dependency on it in one of your controllers. e.g.:
public class ClientsController : ControllerBase
{
private readonly IConfigurationDbContext _configurationDbContext;
public ClientsController(IConfigurationDbContext configurationDbContext)
{
_configurationDbContext = configurationDbContext;
}
// ...
}
IConfigurationDbContext is an abstraction of a standard DbContext, with the following DbSet<T> properties:
Clients
IdentityResources
ApiResources
It also includes both SaveChanges and SaveChangesAsync - Everything one might expect from a DbContext. Because of all of this, you can CRUD each of these entities just like any other Entity Framework Core driven database.
One final thing to note is that there are both Models (in IdentityServer4.Storage) and Entities (in IdentityServer4.EntityFramework.Storage). There are also a few extension methods for mapping between these (e.g. ClientMappers.ToEntity).
Given all of this, you can create a Model inside of your controller (or perhaps somewhere much better encapsulated than directly there). Here's a basic example for creating a new Client:
var clientModel = new Client
{
ClientId = "",
ClientName = "",
// ...
};
_configurationDbContext.Clients.Add(clientModel.ToEntity());
await _configurationDbContext.SaveChangesAsync();
The Client class here comes from IdentityServer4.Models and is then converted to an Entity using a ToEntity extension method I hinted at above. Working with a Model and converting to an Entity is simpler than trying to manipulate an Entity directly - If you're interested, you can see the mapping that takes place here.
This works in the same way for ApiResources, IdentityResources, etc. Use the source code links I've provided if you want to find out more about those specifically, but the information I've provided here should have you covered.
In order to use IdentityServer4 and IdentityServer4.EntityFramework in your API project, you can just add the two references to your API project. After that, you can configure the DI in the same way (using AddIdentityServer in ConfigureServices), but you don't need to add the middleware (using UseIdentityServer in Configure). You can even just use AddIdentityServer().AddConfigurationStore(...) to set up the relevant services, as you don't need a signing key, etc.
One way you can do this is by bootstrapping the ID4 Quickstart (tutorial located here):
http://docs.identityserver.io/en/release/quickstarts/3_interactive_login.html
Other option is to use their quickstart seeds located here to speed this up:
https://github.com/IdentityServer/IdentityServer4.Samples
Now if you want to implement restfull login there are constraints around it (i wanted to find out as well) check out this question:
IdentityServer 4 Restfull Login/Logout

StructureMap and HTTP request-scoped services - why is my service created twice in a single scope?

I have an ASP.NET MVC application using StructureMap.
I have created a service called SecurityContext which has a static Current property. A simplified version looks like this:
public class SecurityContext : ISecurityContext
{
public bool MyProperty { get; private set; }
public static SecurityContext Current
{
get
{
return new SecurityContext() { MyProperty = true };
}
}
}
I've hooked this up in my StructureMap registry as follows:
For<ISecurityContext>().Use(() => SecurityContext.Current);
My understanding of this Linq expression overload of the Use method is that the returned concrete object is the same for the entire HTTP request scope.
However, I've set up a test case where my context interface is injected in two places, once in the controller's constructor and again using the SetterProperty attribute in the base class my view inherits from.
When debugging I observe the Current static method being hit twice so clearly my assumptions are wrong. Can anyone correct what I'm doing here? The reason I want this request-scoped is because I'm loading certain data into my context class from the database so I don't want this to happen multiple times for a given page load.
Thanks in advance.
The default lifecycle for a configuration is Transient, thus each request for an ISecurityContext will create a new instance of SecurityContext. What I think you want is to use the legacy HttpContext lifecycle.
Include the StructureMap.Web nuget package. Then change your configuration to the following:
For<ISecurityContext>()
.Use(() => SecurityContext.Current)
.LifeCycleIs<HttpContextLifecycle>();
More information on lifecyles can be found here.
The HttpContextLifecycle is obsolete, however I do not know if or when it will be removed. The StructureMap team does recommend against using this older ASP.Net lifecycle. They state in the documentation that most modern web frameworks use a nested container per request to accomplish the same scoping. Information about nested containers can be found here.
I don't know if the version of ASP.Net MVC you are using is considered a modern web framework. I doubt it is because ASP.Net Core 1.0 is the really the first in the ASP.Net line to fully embrace the use of DI. However, I will defer to #jeremydmiller on this one.

is there another way of changing Database Instance in Autofac

I have an application that use multiple Database.
i found out i can change that by using the connection builder. like so :
var configNameEf = "ProjectConnection";
var cs = System.Configuration.ConfigurationManager.ConnectionStrings[configNameEf].ConnectionString;
var sqlcnxstringbuilder = new SqlConnectionStringBuilder(cs);
sqlcnxstringbuilder.InitialCatalog = _Database;
but then i need to change the autofac Lifescope of UnitOfWork so that it will now redirect the request to the good Database instance.
what i found out after quite a while is that i can do it like this from a DelegatedHandler :
HttpConfiguration config = GlobalConfiguration.Configuration;
DependencyConfig.Register(config, sqlcnxstringbuilder.ToString());
request.Properties["MS_DependencyScope"] = config.DependencyResolver.GetRequestLifetimeScope();
The question is, is there any other way to do that, that change the MS_DependencyScope parametter of the request. This solution work but i think it is kind of shady.
here is the registry in DependencyConfig:
public static void Register(HttpConfiguration config, String bdContext = null)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.Register(_ => new ProjectContext(bdContext)).As<ProjectContext>().InstancePerApiRequest();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
// Register IMappingEngine
builder.Register(_ => Mapper.Engine).As<IMappingEngine>().SingleInstance();
config.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build());
config.DependencyResolver.BeginScope();
}
The way the question is described and the way the answer to my comment sounds, you have the following situation:
The application uses per-request lifetime units of work. I see this from your registrations.
Only one database is used in the application at a given point in time. That is, each request doesn't have to determine a different database; they all use the same one until the connection string changes. This is seen in the way the database is retrieved from using a fixed application setting.
The connection string in configuration may change, at which point the database used needs to change.
Assuming I have understood the question correctly...
If the app setting is in web.config (as it appears), then changing the string in web.config will actually restart the application. This question talks about that in more detail:
How to prevent an ASP.NET application restarting when the web.config is modified?
If that's the case, you don't have any work to do - just register the database as a singleton and when the web.config changes, the app restarts, re-runs the app startup logic, gets the new database, and magic happens.
If the app setting is not in web.config then you should probably create a project context factory class.
The factory would serve as the encapsulation for the logic of reading configuration and building the connection to the database. It'll also serve as the place to cache the connection for the times when the setting hasn't changed.
The interface would look something like this:
public interface IProjectContextFactory
{
ProjectContext GetContext();
}
A simple implementation (without locking, error handling, logging, and all the good stuff you should put in) might be:
public class ProjectContextFactory : IProjectContextFactory
{
private ProjectContext _currentContext = null;
private string _currentConnectionString = null;
private const string ConnectionKey = "ProjectConnection";
public ProjectContext GetContext()
{
// Seriously, don't forget the locking, etc. in here
// to make this thread-safe! I'm omitting it for simplicity.
var cs = ConfigurationManager.ConnectionStrings[ConnectionKey].ConnectionString;
if(this._currentConnectionString != cs)
{
this._currentConnectionString = cs;
var builder = new SqlConnectionStringBuilder(cs);
builder.InitialCatalog = _Database;
this._currentContext = new ProjectContext(builder.ToString());
}
return this._currentContext;
}
}
OK, now you have a factory that caches the built project context and only changes it if the configuration changes. (If you're not caching the ProjectContext and are, instead, caching the database connection string or something else, the principle still holds - you need a class that manages the caching and checking of the configuration so the change can happen as needed.)
Now that you have a cache/factory, you can use that in your Autofac registrations rather than a raw connection string.
builder.RegisterType<ProjectContextFactory>()
.As<IProjectContextFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<IProjectContextFactory>().GetContext())
.As<ProjectContext>()
.InstancePerRequest();
The ProjectContext will now change on a per request basis when the configured connection string changes.
Aside: I see odd stuff going on with the request lifetime scope. I see in your registration that you're creating your own request lifetime scope. With this method you shouldn't have to do that. If, however, you find that you still need to (or want to), you need to make sure both the originally-created lifetime scope and the one you created are disposed. Lifetime scopes do not get automatically disposed and do hang onto object references so they can handle disposal. There is a high probability that if you're not handling this properly then you have a subtle memory leak. The Autofac Web API integration will take care of creation and disposal of the request lifetime for you, but if you change out the request lifetime, odd things are going to happen.

ServiceStack multiple implementations of same interface in Funq.Container

In ServiceStack application, I have Funq configured to inject a session per request like this:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
My service looks like this, and it works just fine:
public class MyNhAwareService : Service
{
public ISession Session { get; set; }
public object Any(DoSomething request)
{
...
}
}
Now, the problem comes in when I want to add a second NHibernate database into the mix with its own session factory:
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB1);
container.Register<NHibernate.ISession>(c => c.Resolve<NHibernate.ISessionFactory>()
.OpenSession())
.ReusedWithin(Funq.ReuseScope.Request);
// add a different session factory
container.Register<NHibernate.ISessionFactory>(sessionFactoryForDB2);
I've been experimenting with a variety of ways Funq can be used, and I thought I had found the way forward when I discovered the 'RegisterNamed()" method, but that still doesn't help, as I can't use anything except TryResolve() from within my service.
This seems like it should be possible, but I'm beating my head against the wall trying to work it out...Any advice would be greatly appreciated.
You have a couple ways of going about this.
Option 1: Unique Interfaces
This option is to create a distinct interface for each NHibernate database so that they can be uniquely resolved by Funq.
For example:
interface FactoryA : NHibernate.ISessionFactory
{
}
interface FactoryB : NHibernate.ISessionFactory
{
}
You could then proceed as you are now. The same applies for the session. See here for a little more detail about the process:
How to register multiple IDbConnectionFactory instances using Funq in ServiceStack.net
Option 2: Named Instance
This option I am less familiar with, but you can name your instances using Funq:
container.Register<NHibernate.ISessionFactory>("FactoryA",sessionFactoryForDB1);
And then in your service, resolve it thusly:
ServiceStackHost.Instance.Container.ResolveNamed<NHibernate.ISessionFactory>("FactoryA");
This option uses Service Location, which I personally find less attractive.

How can you programatically add mappings to UnicastBusConfig?

I would like to be able to add subscriptions to additional message types living on potentially different servers to my application at runtime. What I'm trying to achieve is a Monitoring application where I can add/remove subscriptions at runtime. Is this possible? How do I get a reference to the current UnicastBus mappings?
Here is what I'm doing so far, but I believe this will overwrite any mappings currently in existence.
MessageEndpointMappingCollection mappings = new MessageEndpointMappingCollection();
mappings.Add(new MessageEndpointMapping()
{
Messages = m.MessageType.ToString(),
Endpoint = m.QueueName
});
IComponentConfig<UnicastBusConfig> busConfig = config.Configurer.ConfigureComponent<UnicastBusConfig>(ComponentCallModelEnum.None);
busConfig.ConfigureProperty(u => u.MessageEndpointMappings, mappings);
Yves used this code in his Azure samples (to be found in NSB samples collection)
using NServiceBus.Config;
using NServiceBus.Config.ConfigurationSource;
namespace OrderService
{
class ConfigOverride : IProvideConfiguration<UnicastBusConfig>
{
public UnicastBusConfig GetConfiguration()
{
return new UnicastBusConfig
{
MessageEndpointMappings = new MessageEndpointMappingCollection
{
new MessageEndpointMapping { Messages="MyMessages", Endpoint="orderserviceinputqueue" }
}
};
}
}
}
The best way to approach this would be to implement IConfigurationSource and provide your own configuration. Then you could cherry pick what you would like to load from the config file (if anything) and what you would like to specify yourself at runtime.
I would reflect the DefaultConfigurationSource class or refer to this gist for guidance.
In a project, I am currently involved with, we are doing some content-based routing to dynamically subscribed/unsubscribed agents by keeping track of them in our own routing table.
We have wrapped the IBus in a decorator (by using Windsor's support of decorators, as described <plug>here</plug>), that sees if the message implements a special IRoutableMessage interface, that allows the decorator to route the message by explicitly specifying the destination endpoint via bus.Send(destinationEndpoint).
This was a little bit complex to get right, and I would recommend going with NServiceBus' built-in routing as far as possible. But is is possible to explicitly route messages to any endpoint.
If you are looking into monitoring, check out the NSBManager repository. This takes the opposite approach and lets the endpoints register with the manager.

Categories

Resources