This question already has answers here:
Dependency Injection wcf
(2 answers)
Closed 6 years ago.
In developing a WPF application that allows editing of article and carrier (pallet, racking) data (in a CRUD-fashion) I'm looking how to manage the lifecycle of the WCF clients connecting to the service that contains the actual data.
I prefer to use an MVVM approach using Caliburn Micro and StructureMap or Castle Windsor.
My main issue is not the creation of WCF client channels or factories, but more important the cleanup after use. I intend to use per-request lifecycle on the server side, as such I will need to create and dispose my clients on a per-request basis. As such I have the following in mind:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
[ServiceContract]
public interface IArticleCrud
{
[OperationContract]
Article CreateArticle(string articleId);
[OperationContract]
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
// Doesn't work since IArticleCrud is not IDisposable
using (var crud = articleCrudFactory())
{
crud.Delete(articleId);
}
}
}
As noted in the comment this won't work because IArticleCrud is not IDisposable. IArticleCrud is used to create a ChannelFactory on the client side to generate proxies for the service implementing the same interface. I'd happily swap out this code for the following:
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IMediator mediator;
public ArticlesViewModel(IMediator mediator)
{
this.mediator = mediator;
}
public void Delete(int articleId)
{
mediator.Send(new DeleteArticleCommand {Id = articleId});
}
}
public class DeleteArticleCommandHandler : RequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
this.articleCrud = articleCrud;
}
protected override void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
However, this doesn't solve my problem as I'm still not dealing with the disposal of the WCF client. I could however make the IMediator create a new nested container on the Send action and have it disposed after the Send action completes, but it seems like a lot of hassle.
Am I getting it all wrong, or does it just require a lot of effort just to perform a WCF call from a WPF application?
As a sidenote, I will be having more services than just these few CRUD services, so the perhaps pragmatic solution of fixing this in my CRUD services is not an option.
I've dealt with the same Problem (WCF-Service used in a WPF Application) and wanted to use the ServiceInterface instead the ServiceClient (which is IDisposable and can be used in a using-block).
One of the solutions to Close the Connection is to cast the Interface to the Client-type and call the .Close()-Method:
public class Article
{
public int Id { get; set; }
public string ArticleId { get; set; }
}
public interface IArticleCrud
{
Article CreateArticle(string articleId);
void Delete(int articleId);
}
public class ArticlesViewModel
{
private readonly Func<IArticleCrud> articleCrudFactory;
public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory)
{
this.articleCrudFactory = articleCrudFactory;
}
public void Delete(int articleId)
{
//Using-Block doesn't work since IArticleCrud is not IDisposable
var crud = articleCrudFactory();
crud.Delete(articleId);
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
}
}
You can also create a static method in your articleCrudFactory that will Close your IArticleCrud:
public static void CloseInterface(IArticleCrud crud)
{
if (crud is ArticleCrud)
(crud as ArticleCrud).Close();
else { ... }
}
I've done it already with WCF and MVVM and its really easy (if I get your problem right):
public interface IRequest
{
}
public interface IRequestHandler<in TCommand> where TCommand : IRequest
{
void HandleCore(TCommand command);
}
public class DeleteArticleCommand : IRequest
{
public int Id { get; set; }
}
public class ArticlesViewModel
{
private readonly IRequestHandler<DeleteArticleCommand> _handler;
public ArticlesViewModel(IRequestHandler<DeleteArticleCommand> handler)
{
_handler = handler;
}
public void Delete(int articleId)
{
_handler.HandleCore(new DeleteArticleCommand { Id = articleId });
}
}
//On client side
public sealed class WcfServiceCommandHandlerProxy<TCommand>
: IRequestHandler<TCommand> where TCommand : IRequest
{
public void HandleCore(TCommand command)
{
using (var service = new ActuaclWcfServiceClient())
{
service.Send(command); //Or however you are working with you WCF client
}
}
}
//Somewhere on server side
public class DeleteArticleCommandHandler : IRequestHandler<DeleteArticleCommand>
{
private readonly IArticleCrud _articleCrud;
public DeleteArticleCommandHandler(IArticleCrud articleCrud)
{
_articleCrud = articleCrud;
}
public void HandleCore(DeleteArticleCommand message)
{
articleCrud.Delete(message.Id);
}
}
Just register your IRequestHandler interface to be implemented with WcfServiceCommandHandlerProxy type and that's it:
//May vary :)
Register(typeof (ICommandHandler<>), typeof (WcfServiceCommandHandlerProxy<>))
Related
I'm very new to ASP.NET Web API and I'm trying to use Entity Framework Core's Dependency Injection to POST data to the API Controller using MediatR pattern. But every time I run my code and it opens Swagger UI, I get an error 500 response saying
Unable to cast object of type 'AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,S3E1.Repository.CartItemRepository+<Createitem>d__5]' to type 'System.Threading.Tasks.Task1[S3E1.Entities.CartItemEntity]'.
First, I added Dependency Injections to Program.cs
//Dependency Injection
builder.Services.AddDbContext<AppDataContext>(contextOptions => contextOptions.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
//Connection
builder.Services.AddSingleton<DataConnectionContext>();
These are the classes.
AppDataContext.cs
public class AppDataContext : DbContext
{
public AppDataContext(DbContextOptions<AppDataContext> contextOptions) : base(contextOptions) { }
public DbSet<CartItemEntity> CartItems { get; set; }
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<UserEntity> Users{ get; set; }
}
DataConnectionContext.cs
public class DataConnectionContext
{
private readonly IConfiguration _configuration;
private readonly string _connectionString;
public DataConnectionContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = _configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
}
Next is making a repository which holds the interface that has the create method.
public interface ICartItemRepository
{
//public Task<IEnumerable<CartItemEntity>> GetCartItems();
//public Task<CartItemEntity> GetCartItemEntity(Guid id);
public Task Createitem(CartItemEntity itemEntity);
}
Then a class that inherits the interface and calls the dependency constructors
public class CartItemRepository : ICartItemRepository
{
private readonly DataConnectionContext _connectionContext;
private readonly AppDataContext _appDataContext;
public CartItemRepository(DataConnectionContext connectionContext, AppDataContext appDataContext)
{
_connectionContext = connectionContext;
_appDataContext = appDataContext;
}
public async Task Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
await _appDataContext.CartItems.ToListAsync();
}
}
Next is a command for POST request MediatR pattern
public record AddCartItemCommand(CartItemEntity cartItem) : IRequest<CartItemEntity>;
and a Handler which manages and returns the method createitem
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
private readonly ICartItemRepository _cartItemRepository;
public AddItemsHandler(ICartItemRepository cartItemRepository) => _cartItemRepository = cartItemRepository;
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await (Task<CartItemEntity>) _cartItemRepository.Createitem(request.cartItem);
}
}
and lastly, in the controller
[Route("api/cart-items")]
[ApiController]
public class CartItemsController : ControllerBase
{
private ISender _sender;
public CartItemsController(ISender sender) => _sender = sender;
[HttpPost]
public async Task<CartItemEntity> Post(CartItemEntity cartItemEntity)
{
return await _sender.Send(new AddCartItemCommand(cartItemEntity));
}
}
I tried modifying the return object in the handler but every time I change anything it always get the error squiggly line, so I just casted the (Task) after the await. Is this where I went wrong? Thank you for any answers.
The exception is clear. You can't cast a VoidTaskResult to Task<CartItemEntity>.
To solve the problem:
In ICartItemRepository, modify the return type for Createitem as Task<CartItemEntity>.
In CartItemRepository, implement Createitem method from the ICartItemRepository interface. Return the inserted itemEntity in the method.
Since you have implemented Task<CartItemEntity> Createitem(CartItemEntity itemEntity) in the ICartItemRepository interface, the casting to (Task<CartItemEntity>) is no longer needed, and suggested to be removed.
public interface ICartItemRepository
{
...
public Task<CartItemEntity> Createitem(CartItemEntity itemEntity);
}
public class CartItemRepository : ICartItemRepository
{
...
public async Task<CartItemEntity> Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
return itemEntity;
}
}
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
...
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await _cartItemRepository.Createitem(request.cartItem);
}
}
My working SignalR ASP.NET Core 5 Windows Service with a simple string payload (or even more value type parameters) does not work anymore when I change it to a (simple) complex object ("CommonMessage" in my case). From what I read, it should work out of the box. The "SendCommonMessage" method doesn't get called anymore and I am not getting any error. What am I missing? Is there no way of debugging/getting the error shown? (The ASP.NET Service gets called by a WPF Core 5 application.)
public class CommonMessageHub : Hub
{
public async Task SendCommonMessage(CommonMessage commonMessage)
{
await Clients.All.SendAsync("ReceiveCommonMessage", commonMessage);
}
}
public class CommonMessage
{
public int MessageType { get; set; }
public int Id { get; set; }
public string Text { get; set; }
}
The caller (WPF app) looks like so:
public class CommonMessageService
{
public CommonMessageService(HubConnection connection)
{
_connection = connection;
_connection.On<CommonMessage>("ReceiveCommonMessage", commonMessage => CommonMessageReceived?.Invoke(commonMessage));
}
private readonly HubConnection _connection;
public event Action<CommonMessage> CommonMessageReceived;
public async Task Connect()
{
await _connection.StartAsync();
}
public async Task SendCommonMessage(CommonMessage commonMessage)
{
await _connection.SendAsync("SendCommonMessage", commonMessage);
}
}
I have NotificationJob class where I have all the functions related to Notification Feature for my .Net Core application. It has some injected dependencies from Domain services. I am having a problem trying to inject INotificationJob interface of the class into the CoreModule of the project.
I initially tried injecting the interface directly into the CoreModule but failed so I created another module in the same file called NotificationModule where I inject INotificationJob interface. Then I try to link it with the CoreModule using [DependsOn(typeof(oasisCoreModule))] annotation.
Core Module of the project
[DependsOn(
typeof(AbpZeroCoreModule),
typeof(AbpHangfireAspNetCoreModule),
typeof(AbpWebCommonModule)
)]
public class oasisCoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Modules.AbpWebCommon().SendAllExceptionsToClients = true;
Configuration.BackgroundJobs.UseHangfire();
Configuration.Auditing.IsEnabledForAnonymousUsers = true;
// Declare entity types
Configuration.Modules.Zero().EntityTypes.Tenant = typeof(Tenant);
Configuration.Modules.Zero().EntityTypes.Role = typeof(Role);
Configuration.Modules.Zero().EntityTypes.User = typeof(User);
oasisLocalizationConfigurer.Configure(Configuration.Localization);
// Enable this line to create a multi-tenant application.
Configuration.MultiTenancy.IsEnabled = oasisConsts.MultiTenancyEnabled;
// Configure roles
AppRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
Configuration.Settings.Providers.Add<AppSettingProvider>();
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(oasisCoreModule).GetAssembly());
}
public override void PostInitialize()
{
IocManager.Resolve<AppTimes>().StartupTime = Clock.Now;
}
}
// This is the custom module that I created in the same file as the core module.
[DependsOn(typeof(oasisCoreModule))]
public class NotificationModule : AbpModule
{
INotificationJob _job;
public NotificationModule(INotificationJob job)
{
_job = job;
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
public override void PostInitialize()
{
_job.Loop();
}
}
INotificationJob Interface I am Injecting into the NotificationModule
public interface INotificationJob: IDomainService
{
void Loop();
void CheckTickets();
void CheckReminders(string email, string ticket);
}
Class Implementation of INotificationJob Interface
public class NotificationJob: DomainService, INotificationJob
{
private readonly ITicketRefManager _ticketRefManager;
private readonly IClientManager _clientManager;
private readonly IEmailManager _emailManager;
public NotificationJob(
ITicketRefManager ticketRefManager,
IClientManager clientManager,
IEmailManager emailManager,
)
{
_ticketRefManager = ticketRefManager;
_clientManager = clientManager;
_emailManager = emailManager;
}
public void Loop()
{
RecurringJob.AddOrUpdate(() => CheckTickets(), Cron.Minutely);
}
}
When I run the solution, I am presented with an error saying as shown:
Are there any other steps that I need to take to complete the Dependency Injection process? Or are the steps that I described flawed?
I'm not sure what you're trying to do with you "interface injecting", but you can try this if I understand correctly what you're trying to do :
Core Module
[...]
public override void PostInitialize()
{
var recurrentJobs = IocManager.Resolve<NotificationJob>();
RecurringJob.RemoveIfExists("JobName");
RecurringJob.AddOrUpdate("JobName", () => recurrentJobs.CheckTickets(), Cron.Minutely);
}
Your class
public class NotificationJob : ISingletonDependency
{
private readonly ITicketRefManager _ticketRefManager;
private readonly IClientManager _clientManager;
private readonly IEmailManager _emailManager;
public NotificationJob(
ITicketRefManager ticketRefManager,
IClientManager clientManager,
IEmailManager emailManager,
)
{
_ticketRefManager = ticketRefManager;
_clientManager = clientManager;
_emailManager = emailManager;
}
public void CheckTickets()
{
//Do something
}
}
Does it helps ?
NotificationHubConnectionSettings.cs file to fetch connection string from web.config
public class NotificationHubConnectionSettings
{
public NotificationHubClient Hub { get; set; }
public NotificationHubConnectionSettings()
{
Hub = NotificationHubClient.CreateClientFromConnectionString(ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.ConnectionString"], ConfigurationManager.AppSettings["NotificationHub"]);
}
}
Inside Bootstrapper.cs
using Unity dependency injection nuget
private static IUnityContainer BuildUnityContainer()
{
try
{
var container = new UnityContainer();
container.RegisterType<NotificationHubConnectionSettings>().RegisterType<NotificationHubConnectionSettings>(new HierarchicalLifetimeManager());
return container;
}
catch (Exception)
{
return null;
}
}
In HomeController.cs
want to implement dependency injection -
private readonly NotificationHubClient _hub;
public HomeController(NotificationHubConnectionSettings hub)
{
_hub = hub.Hub;
}
// POST api/register
// This creates a registration id
public async Task<string> Post(string handle = null)
{
string newRegistrationId = null;
if (handle != null)
{
var registrations = await _hub.GetRegistrationsByChannelAsync(handle, 100);
Is this correct way to implement dependency injection?
You should be using a interface type here.
Create a contract for INotificationHubConnectionSettings class in the form of a interface which dictates to your system all public methods and properties available.
public interface INotificationHubConnectionSettings
{
NotificationHubClient Hub { get; set; }
}
Then have your actual NotificationHubConnectionSettings class inherit from this interface;
public class NotificationHubConnectionSettings : INotificationHubConnectionSettings
{
public NotificationHubClient Hub { get; set; }
public NotificationHubConnectionSettings()
{
Hub = NotificationHubClient.CreateClientFromConnectionString(ConfigurationManager.AppSettings["Microsoft.Azure.NotificationHubs.ConnectionString"], ConfigurationManager.AppSettings["NotificationHub"]);
}
}
Now register the interface and class inside of UnityContainer and change your constructor to the following;
private readonly INotificationHubClient _hub;
public HomeController(NotificationHubConnectionSettings hub)
{
_hub = hub.Hub;
}
Always use interfaces for dependency injection.
I am starting to use Ninject in my MVC5 code-first app. Here's my NinjectWebCommon.cs:
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
kernel.Bind<CMSContext>()
.ToSelf()
//.InSingletonScope();
.InRequestScope();
kernel.Bind<IExecutiveRepository>()
.To<ExecutiveRepository>();
kernel.Bind<IExecutiveSectionRepository>()
.To<ExecutiveSectionRepository>();
kernel.Bind<IExecutiveSectionMappingRepository>()
.To<ExecutiveSectionMappingRepository>();
kernel.Bind<IUserRepository>()
.To<UserRepository>();
kernel.Bind<IContentRepository>()
.To<ContentRepository>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
I tried .InSingletonScope() as well as .InRequestScope() but I still get the 'entity object cannot be referenced by multiple instances of IEntityChangeTracker' error.
Here is my Interface:
public interface IExecutiveRepository : IDisposable
{
IEnumerable<Executive> GetExecutives();
Executive GetExecutiveById(int executiveId);
void InsertExecutive(Executive executive);
void UpdateExecutive(Executive executive);
void DeleteExecutive(int executiveId);
void Save();
}
Here is my concrete:
public class ExecutiveRepository : IExecutiveRepository, IDisposable
{
private CMSContext context;
public ExecutiveRepository(CMSContext context)
{
this.context = context;
}
public IEnumerable<Executive> GetExecutives()
{
return context.Executives.ToList();
}
public Executive GetExecutiveById(int id)
{
return context.Executives.Find(id);
}
public void InsertExecutive(Executive executive)
{
context.Executives.Add(executive);
}
public void DeleteExecutive(int executiveId)
{
Executive executive = context.Executives.Find(executiveId);
context.Executives.Remove(executive);
}
public void UpdateExecutive(Executive executive)
{
context.Entry(executive).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Here is the controller(top pertinent part):
public class ExecutiveController : Controller
{
private IExecutiveRepository executiveRepository;
private IUserRepository userRepository;
private IExecutiveSectionRepository executiveSectionRepository;
private IExecutiveSectionMappingRepository executiveSectionMappingRepository;
private IContentRepository contentRepository;
private Ninject.IKernel _kernel = new StandardKernel();
//[Inject]
public ExecutiveController()
{
executiveRepository = _kernel.Get<ExecutiveRepository>();
userRepository = _kernel.Get<UserRepository>();
executiveSectionRepository = _kernel.Get<ExecutiveSectionRepository>();
executiveSectionMappingRepository = _kernel.Get<ExecutiveSectionMappingRepository>();
contentRepository = _kernel.Get<ContentRepository>();
}
...
Not sure what I am doing wrong but upon adding a new 'Executive' it bombs... I do understand it's trying to use separate contexts and that's the problem, but I 'm just not sure how to fix it. Apparently, the line in the NinjectWebCommon.cs class:
kernel.Bind<CMSContext>()
.ToSelf()
//.InSingletonScope();
.InRequestScope();
Is supposed to be the fix, but it isn't...
any ideas/suggestions?
You should be using NUGET package Ninject.Web.Mvc if you aren't already. This configures your application ready to use Ninject, other than your bindings. It looks like you are reasonably familiar with the bindings side of things already from what I can see in your CreateKernel() method.
Once your bindings are in place, you should not be creating Kernels in your controllers, this is because the Ninject.Web.Mvc library configures Ninject to create your controllers for you under the hood. Therefore any dependencies that you add to them should be automatically resolved.
So, you can use constructor injection to resolve your dependencies:
public class ExecutiveController : Controller
{
private IExecutiveRepository ExecutiveRepository;
private IUserRepository UserRepository;
private IExecutiveSectionRepository ExecutiveSectionRepository;
private IExecutiveSectionMappingRepository ExecutiveSectionMappingRepository;
private IContentRepository ContentRepository;
public ExecutiveController(
IExecutiveRepository executiveRepository,
IUserRepository userRepository,
IExecutiveSectionRepository executiveSectionRepository,
IExecutiveSectionMappingRepository executiveSectionMappingRepository,
IContentRepository contentRepository)
{
// Set the field values
this.ExecutiveRepository = executiveRepository,
this.UserRepository = userRepository,
this.ExecutiveSectionRepository = executiveSectionRepository,
this.ExecutiveSectionMappingRepository = executiveSectionMappingRepository,
this.ContentRepository = contentRepository;
}
public ActionResult Index(int id)
{
// Use one of your dependencies...
var executive = this.executiveRepository.GetExecutiveById(id);
}
}
Or you can use the [Inject] attribute which has the same effect:
public class ExecutiveController : Controller
{
[Inject]
public IExecutiveRepository executiveRepository { get; set; }
[Inject]
public IUserRepository userRepository { get; set; }
[Inject]
public IExecutiveSectionRepository executiveSectionRepository { get; set; }
[Inject]
public IExecutiveSectionMappingRepository executiveSectionMappingRepository { get; set; }
[Inject]
public IContentRepository contentRepository { get; set; }
public ExecutiveController()
{
}
public ActionResult Index(int id)
{
// Use one of your dependencies...
var executive = this.executiveRepository.GetExecutiveById(id);
}
}
You're creating a kernel per controller.
InRequestScope only ensures one instance per request per kernel.
So you need to adapt your setup of the kernel so there's only one kernel per web application. See:
Ninject.Web.Mvc
Tutorial
Youtube
This may not answer the question. But I tend to use the IDbContextFactory that EF provides you with and do something like this:
public interface IDefaultContextFactory : IDbContextFactory<CMSContext> {}
public class DefaultContextFactory : IDefaultContextFactory
{
private readonly Lazy<CMSContext> lazyContext = new Lazy<CMSContext>(() => new CMSContext());
public CMSContext Create()
{
return lazyContext.Value;
}
}
Then you just bind that, and when you need the context you can do something like this:
public class ExecutiveRepository : IExecutiveRepository, IDisposable
{
private readonly CMSContext context;
public ExecutiveRepository(IDefaultContextFactory contextFactory)
{
this.context = contextFactory.Create();
}
}
I believe #BatteryBackupUnit is correct, I would also consider using the above pattern for contexts.