I want to inject #ConnectedSocket into a nestjs service that provides an interface for event emitting. The goal is pretty clear - to avoid calling emit with raw event name and any data. SocketFacadeHost below is an example of such a service.
So far the only way I could think of is replacing each emit call by wrapping socket with a facade service factory - SocketFacade.
socket.facade.ts
class SocketFacadeHost {
constructor(private client: Socket) { }
syncDSL(dsl: CoreDSL): void {
this.client.emit('syncDSL', dsl);
}
}
export const SocketFacade = (client: Socket) => new SocketFacadeHost(client);
socket.gateway.ts
...
#SubscribeMessage('bind')
async bindEnvironment(
#MessageBody() data: BindingDTO,
#ConnectedSocket() client: Socket,
): Promise<void> {
const { pageUUID } = data;
const page = await this.pagesService.getByUUID(pageUUID);
SocketFacade(client).syncDSL(page.coreDSL);
}
But that is still kinda hackish. Any straightforward way of doing this?
Something like extending #ConnectedSocket decorator or WebSocketGateway?
--- Edit 1 ---
After going through tons of documentation, examples and issues on the subject, I believe the problem lies in the idea of making the service aware of context, that is by default incorrect. Thus guards, interceptors, pipes and all the ExecutionContext decorators only work on the controller/gateway level. Service should either be stateless or instantiated all over on each call (which is controlled by the #Injectable scope).
So my approach of using the facade factory is OK.
But then again, it would be convenient if it was possible to 'replace' #ConnectedSocket() decorator by a decorator that returns wrapped socket with an interface, that wouldn't mess with clean mvc.
In the end, I settled with hacking my own 'dependency injection'. Since request scope is not an option for WebSocketGateway, I decided to manually instantiate and cleanup the needed services and store them within Socket client with additional storage interface.
This way I have ConnectedSocket-scoped classes that can communicate to one another, while still having an access to global scoped injections (that have to be manually passed down to all the classes through gateway).
Given approach solves all the problems, while keeping everything dry and in sync with the idea that some day ConnectedSocket-scopes may be added to NestJS.
Related
After see this documentation I'm not sure if to use a simple context, as I has done other times, or if it is better to use dataSources to handle the database.
DataSource is the correct way to comunicate with the database or it is better use it only to comunicate with a REST API?
Basically, does it have any advantage to use dataSources vs context in this case?
I think it's better to go with DataSource (as the name suggests) and it might be easy to add a caching layer on top of it. You can create a DBDataSource class extending the DataSource class since Apollo doesn't provide any DBDataSource class.
DataSource class is a generic Apollo data source class whereas RESTDataSource class that is responsible for fetching data from a REST API.
So to fetch data from rest APIs it's better to go with RESTDataSource.
Build a custom data source
Apollo doesn't have support for a SQL data source yet (although we'd love to help guide you if you're interested in contributing), so we will need to create a custom data source for our database by extending the generic Apollo data source class. You can create your own with the apollo-datasource package.
Here are some of the core concepts for creating your own data source:
The initialize method: You'll need to implement this method if you want to pass in any configuration options to your class. Here, we're using this method to access our graph API's context.
this.context: A graph API's context is an object that's shared among every resolver in a GraphQL request. We're going to explain this in more detail in the next section. Right now, all you need to know is that the context is useful for storing user information.
Caching: While the REST data source comes with its own built-in cache, the generic data source does not. You can use our cache primitives to build your own, however!
I generally keep resolvers very thin, pass the incoming args to dataSources and they make models and loaders communicate. Most of the logic and validations are in models. You may of course make your own rules like "don't call another dataSource inside a dataSource. Pass their outpus to make them communicate through resolvers" etc. This is only an example of course. Not a strict rule I follow.
There may be better solutions and actually for simple things, using models directly is much more straightforward. But dataSources help you keep things organised and if you want to add caching etc, you can create a BaseDataSource, put all the logic in that and just extend it with other dataSources.
If you look at the documentation that your pointed out. You add data Sources when initializing Apollo Server like this :
const server = new ApolloServer({
typeDefs,
dataSources: () => ({
launchAPI: new LaunchAPI(),
userAPI: new UserAPI({ store })
})
});
and it is because of this dataSources becomes the part of context. If you remember you do the de-structuring of context to expose dataSources as shown here
module.exports = {
Query: {
launches: (_, __, { dataSources }) =>
dataSources.launchAPI.getAllLaunches(),
launch: (_, { id }, { dataSources }) =>
dataSources.launchAPI.getLaunchById({ launchId: id }),
me: (_, __, { dataSources }) => dataSources.userAPI.findOrCreateUser()
}
};
If you want to access the instance of a dataSource such as UserAPI or LaunchAPI, you will have to do that with dataSources.userAPI
We seem to have done something to introduce some kind of threading issue into our app. It's a dotnet core 1.1.2 application, using EntityFrameworkCore. Intermittently, but reproducably, we will get one of these errors:
System.InvalidOperationException: 'The connection was not closed. The connection's current state is open.' exception when running an EF query.
or
System.InvalidCastException: 'Unable to cast object of type 'System.Data.ProviderBase.DbConnectionClosedConnecting' to type 'System.Data.SqlClient.SqlInternalConnectionTds'.'
or
System.ObjectDisposedException: 'Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.'
This can happen at almost any point in the app, but this method seems to be the most frequent culprit (this does get called somewhat frequently):
public class WidgetConfigurationRepository : IWidgetConfigurationRepository
{
public WidgetConfigurationRepository(LocalContext dataContext)
{
Context = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
}
private LocalContext _context { get; private set; }
public async Task<WidgetConfiguration> LoadConfigurationAsync(Guid widgetId)
{
return await _context.WidgetConfigurations
.Include(x => x.Options)
.FirstOrDefaultAsync(x => x.WidgetId.Equals(widgetId));
}
...
}
the repository is created via the Core DI container, and is injected at runtime:
services.AddScoped<IWidgetConfigurationRepository, WidgetConfigurationRepository>();
The Repository and the LocalContext are both registered as Scoped, and there are no Singleton accessors of the LocalContext.
Walking through the stack trace (and the parallel stacks) shows that every async method is awaited, and I have gone through replacing the interfaces in the application with the implementations, to hopefully try to find any async without await.
The LocalContext itself is created via a LocalDbContextFactory that is also registered as Scoped. It reads data from a central data context, checks some data and then instantiates a new instance of the LocalContext. This is only happening once per request, as expected.
Ultimately, I'm looking for some help working out what could be causing this, our app is now fairly large and I'm not sure I can provide enough code snippets to help.
At the moment, I think my best option is to write a Roslyn analyzer to go through all the methods that return Task or Task<T> and check that something happens with the return object, but I'm wondering if there is something easier that I may have missed.
There is this related question: EF. The connection was not closed. The connection's current state is connecting
with the
Re-check that IUserService is registered with "scope" lifetime, and all it dependencies (userManager, dbContext) too
Do not use IServiceProvider you obtained during app startup for scope-bases services resolution - it is NOT related to current request scope and return instances from "some other universe". Use HttpContext.RequestServices for service resolution.
Check that your are "awaiting" all async methods. If you start second request while still executing first one - you may possibly "catch" dbContext during "connecting" stage.
Your JwtMessageHandler instance is one/single per app. So don't use it's property for storing _userService (remove private IUserService _userService). Instead, use local variable inside OnMessageReceived (var _userService = ...).
As far as I can tell, we are not being caught by any of these, almost all of our services are Scoped or Transient.
We use ServiceProvider.GetService<>() during the app startup, to resolve the database to run Migrations on, but not beyond that.
I think it's possible that there is an async without an await, but I don't seem to be able to find it, and we aren't getting compiler warnings for it.
I need add membership reboot (RavenDb) into the project that use IOC Simple Injector
Ninject implementation
var config = MembershipRebootConfig.Create();
kernel.Bind<MembershipRebootConfiguration<HierarchicalUserAccount>>().ToConstant(config);
kernel.Bind<UserAccountService<HierarchicalUserAccount>>().ToSelf(); kernel.Bind<AuthenticationService<HierarchicalUserAccount().To<SamAuthenticationService<HierarchicalUserAccount>>();
kernel.Bind<IUserAccountRepository<HierarchicalUserAccount>>().ToMethod(ctx => new BrockAllen.MembershipReboot.RavenDb.RavenUserAccountRepository("RavenDb"));
kernel.Bind<IUserAccountQuery>().ToMethod(ctx => new BrockAllen.MembershipReboot.RavenDb.RavenUserAccountRepository("RavenDb"));
Simple Injector implementation
container.Register(MembershipRebootConfig.Create);
container.Register<UserAccountService<HierarchicalUserAccount>>();
container.Register<AuthenticationService<HierarchicalUserAccount>, SamAuthenticationService<HierarchicalUserAccount>>();
container.Register<IUserAccountRepository<HierarchicalUserAccount>>(() => new RavenUserAccountRepository("RavenDb"), Lifestyle.Singleton);
container.Register<IUserAccountQuery>(() => new RavenUserAccountRepository("RavenDb"));
On row
container.Register<UserAccountService<HierarchicalUserAccount>>();
I have an error
For the container to be able to create UserAccountService, it should contain exactly one public constructor, but it has 2.
Parameter name: TConcrete
Thanks for your help.
Simple Injector forces you to let your components to have one single public constructor, because having multiple injection constructors is an anti-pattern.
In case the UserAccountService is part of your code base, you should remove the constructor that should not be used for auto-wiring.
In case the UserAccountService is part of a reusable library, you should prevent using your container's auto-wiring capabilities in that case as described here. In that case you should fallback to wiring the type yourself and let your code call into the proper constructor, for instance:
container.Register<UserAccountService<HierarchicalUserAccount>>(() =>
new UserAccountService<HierarchicalUserAccount>(
container.GetInstance<MembershipRebootConfiguration<HierarchicalUserAccount>>(),
container.GetInstance<IUserAccountRepository<HierarchicalUserAccount>>()));
I'm just going to include here how I converted the Ninject configuration to Simple Injector for the Single Tenant sample in the MembershipReboot repository (which I cloned). I thought that might be beneficial for anyone who was searching for how to go about this, as it may save them some time.
Firstly, the configuration in the Single Tenant sample's NinjectWebCommon class is:
var config = MembershipRebootConfig.Create();
kernel.Bind<MembershipRebootConfiguration>().ToConstant(config);
kernel.Bind<DefaultMembershipRebootDatabase>().ToSelf();
kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
Now, I'll set out the whole SimpleInjectorInitializer class, which started with the one which was added to the project via the SimpleInjector.MVC3 Nuget package, and follow up with comments:
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
InitializeContainer(container);
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
var config = MembershipRebootConfig.Create();
container.Register(() => config, Lifestyle.Singleton);
container.Register(() => new DefaultMembershipRebootDatabase(), Lifestyle.Scoped);
container.Register<IUserAccountQuery, DefaultUserAccountRepository>(Lifestyle.Scoped); // per request scope. See DefaultScopedLifestyle setting of container above.
container.Register<IUserAccountRepository, DefaultUserAccountRepository>(Lifestyle.Scoped);
container.Register(() => new UserAccountService(container.GetInstance<MembershipRebootConfiguration>(), container.GetInstance<IUserAccountRepository>()));
container.Register<AuthenticationService, SamAuthenticationService>();
var iUserAccountQueryRegistration = container.GetRegistration(typeof(IUserAccountQuery)).Registration;
var iUserAccountRepositoryRegistration = container.GetRegistration(typeof(IUserAccountRepository)).Registration;
iUserAccountQueryRegistration.SuppressDiagnosticWarning(DiagnosticType.TornLifestyle, "Intend for separate Objects");
iUserAccountRepositoryRegistration.SuppressDiagnosticWarning(DiagnosticType.TornLifestyle, "Intend for separate Objects");
}
}
Scoping the config to a Singleton with a factory func is pretty much the same as Ninject's ToConstant.
DefaultMembershipRebootDatabase is the obvious departure, but I honestly don't think it matters whether MR's DefaultMembershipRebootDatabase is scoped a transient or per web request. It calls SaveChanges every time an operation is performed e.g. Registering a user. It does not use larger, per request-bound tansactions. So, using the same DefaultMembershipRebootDatabase context later in the same request is no going to cause any weird MR issues.
HOWEVER, some thought will need to given to what happens if you want to create a Domain User during the same operation as you create a MR UserAccount. (A Domain User may contain more information beyond password stuff, like first and last names, DOB etc.). Tying an MR UserAccount to a Domain User (with additional user info such a name, address etc.) is a common use case. So what happens if the creation of the Domain User fails after creation of the MR UserAccount succeeded? I don't know. Perhaps as part of the rollback, you delete the MR user. But the registration email will already have been sent. So, these are the issues that you face here.
As you can see, in the Simple Tenant sample, Brock registers both IUserAccountRepository and IUserAccountQuery to DefaultUserAccountRepository. This is obviously by design and so we have to do that as well, if we want to use MR's UserAccountService and AuthenticationService. Thus, we need to suppress the Diagnostic warnings which would otherwise prevent the Container from Verifying.
Hope that all helps and by all means let me know if there are problems with my registrations.
Cheers
I've built some code that can rebuild expression trees so I can avoid triggering the no supported translation to SQL exception and it works fine as long as I call my function to replace the iqueryable. The problem is that I'd like it to automatically be applied to all queries in my project without having to worry about calling this function on each one separately. Is there any way that I can intercept everything?
I've tried using Reflection.Emit to create a wrapping provider and using reflection to replace it on the data context and it turns out that even with Reflection.Emit I can't implement the internal IProvider interface.
I've also tried replacing the provider with a RealProxy based class and that works for non-compiled queries, but the CompiledQuery.Execute method is throwing an exception because it won't cast to the SqlProvider class. I tried replacing the response to the Compile method on the provider with another proxy so I could intercept the Execute call, but that failed a check on the return type being correct.
I'm open to any other ideas or ways of using what I've already tried?
It's hard to tell whether this is an applicable solution without seeing your code, but if you have a DI-friendly app architecture you can implement an interceptor and have your favorite IoC container emit the appropriate type for you, at run-time.
Esoteric? A little. Consider an interface like this:
public interface ISomeService
{
IEnumerable<SomeEntity> GetSomeEntities();
// ...
}
This interface might be implemented like this:
public class SomeService : ISomeService
{
private readonly DbContext _context // this is a dependency!
private readonly IQueryTweaker _tweaker; // this is a dependency!
public SomeService(DbContext context, IQueryTweaker tweaker) // this is constructor injection!
{
_context = context;
_tweaker = tweaker;
}
public IEnumerable<SomeEntity> GetSomeEntities()
{
return _tweaker.TweakTheQuery(_context.SomeEntities).ToList();
}
}
Every time you implement a method of the ISomeService interface, there's always a call to _tweaker.TweakTheQuery() that wraps the IQueryable, and that not only gets boring, it also feels like something is missing a feature - the same feeling you'd get by wrapping every one of these calls inside a try/catch block, or if you're familiar with MVVM in WPF, by raising this annoying PropertyChanged event for every single property setter in your ViewModel.
With DI Interception, you factor this requirement out of your "normal" code and into an "interceptor": you basically tell the IoC container that instead of binding ISomeService directly to the SomeService implementation, you're going to be decorating it with an interceptor, and emit another type, perhaps SomeInterceptedService (the name is irrelevant, the actual type only exists at run-time) which "injects" the desired behavior into the desired methods. Simple? Not exactly.
If you haven't designed your code with DI in mind (are your dependencies "injected" into your classes' constructor?), it could mean a major refactoring.
The first step breaks your code: remove the IQueryTweaker dependency and all the TweakTheQuery calls from all ISomeService implementations, to make them look like this - notice the virtualness of the method to be intercepted:
public class SomeService : ISomeService
{
private readonly DbContext _context
public SomeService(DbContext context)
{
_context = context;
}
public virtual IEnumerable<SomeEntity> GetSomeEntities()
{
return _context.SomeEntities.ToList();
}
}
The next step is to configure the IoC container so that it knows to inject the SomeService implementation whenever a type's constructor requires an ISomeService:
_kernel.Bind<ISomeService>().To<SomeService>();
At that point you're ready to configure the interception - if using Ninject this could help.
But before jumping into that rabbit's hole you should read this article which shows how decorator and interceptor are related.
The key point is, you're not intercepting anything that's internal to LINQ to SQL or the .NET framework itself - you're intercepting your own method calls, wrapping them with your own code, and with a little bit of help from any decent IoC container, you'll be intercepting the calls to methods that call upon Linq to SQL, rather than the direct calls to Linq to SQL itself. Essentially the IQueryTweaker dependency becomes a dependency of your interceptor class, and you'll only code its usage once.
An interesting thing about DI interception, is that interceptors can be combined, so you can have a ExecutionTimerServiceInterceptor on top of a AuditServiceInterceptor, on top of a CircuitBreakerServiceInterceptor... and the best part is that you can configure your IoC container so that you can completely forget it exists and, as you add more service classes to the application, all you need to do is follow a naming convention you've defined and voilĂ , you've just written a service that not only accomplishes all the strictly data-related tasks you've just coded, but also a service that will disable itself for 3 minutes if the database server is down, and will remain disabled until it's back up; that service also logs all inserts, updates and deletes, and stores its execution time in a database for performance analysis. The term automagical seems appropriate.
This technique - interception - can be used to address cross-cutting concerns; another way to address those is through AOP, although some articles (and Mark Seeman's excellent Dependency Injection in .NET) clearly demonstrate how AOP frameworks are a less ideal solution over DI interception.
This question may be more appropriate for the Programmers stack. If so, I will move it. However I think I may get more answers here.
So far, all interface dependencies in my domain are resolved using DI from the executing assembly, which for now, is a .NET MVC3 project (+ Unity IoC container). However I've run across a scenario where I think service locator may be a better choice.
There is an entity in the domain that stores (caches) content from a URL. Specifically, it stores SAML2 EntityDescriptor XML from a metadata URL. I have an interface IConsumeHttp with a single method:
public interface IConsumeHttp
{
string Get(string url);
}
The current implementation uses the static WebRequest class in System.Net:
public class WebRequestHttpConsumer : IConsumeHttp
{
public string Get(string url)
{
string content = null;
var request = WebRequest.Create(url);
var response = request.GetResponse();
var stream = response.GetResponseStream();
if (stream != null)
{
var reader = new StreamReader(stream);
content = reader.ReadToEnd();
reader.Close();
stream.Close();
}
response.Close();
return content;
}
}
The entity which caches the XML content exists as a non-root in a much larger entity aggregate. For the rest of the aggregate, I am implementing a somewhat large Facade pattern, which is the public endpoint for the MVC controllers. I could inject the IConsumeHttp dependency in the facade constructor like so:
public AnAggregateFacade(IDataContext dataContext, IConsumeHttp httpClient)
{
...
The issue I see with this is that only one method in the facade has a dependency on this interface, so it seems silly to inject it for the whole facade. Object creation of the WebRequestHttpConsumer class shouldn't add a lot of overhead, but the domain is unaware of this.
I am instead considering moving all of the caching logic for the entity out into a separate static factory class. Still, the code will depend on IConsumeHttp. So I'm thinking of using a static service locator within the static factory method to resolve IConsumeHttp, but only when the cached XML needs to be initialized or refreshed.
My question: Is this a bad idea? It does seem to me that it should be the domain's responsibility to make sure the XML metadata is appropriately cached. The domain does this periodically as part of other related operations (such as getting metadata for SAML Authn requests & responses, updating the SAML EntityID or Metadata URL, etc). Or am I just worrying about it too much?
It does seem to me that it should be the domain's responsibility to
make sure the XML metadata is appropriately cached
I'm not sure about that, unless your domain is really about metadata manipulation, http requests and so on. For a "normal" application with a non-technical domain, I'd rather deal with caching concerns in the Infrastructure/Technical Services layer.
The issue I see with this is that only one method in the facade has a
dependency on this interface, so it seems silly to inject it for the
whole facade
Obviously, Facades usually don't lend themselves very well to constructor injection since they naturally tend to point to many dependencies. You could consider other types of injection or, as you pointed out, using a locator. But what I'd personnaly do is ask myself if a Facade is really appropriate and consider using finer-grained objects instead of the same large interface in all of my controllers. This would allow for more modularity and ad-hoc injection rather than inflating a massive object upfront.
But that may just be because I'm not a big Facade fan ;)
In your comment to #ian31, you mention "It seems like making the controller ensure the domain has the correct XML is too granular, giving the client too much responsibility". For this reason, I'd prefer the controller asks its service/repository (which can implement the caching layer) for the correct & current XML. To me, this responsibility is a lot to ask of the domain entity.
However, if you're OK with the responsibilities you've outlined, and you mention the object creation isn't much overhead, I think leaving the IConsumeHttp in the entity is fine.
Sticking with this responsibility, another approach could be to move this interface down into a child entity. If this was possible for your case, at least the dependency is confined to the scenario that requires it.