Given the following code for my connection factory:
public interface IDbFrontEndConnectionFactory : IDbConnectionFactory
{
}
public class FrontEndDbFactory : IDbFrontEndConnectionFactory
{
private readonly IAppSettings _settings;
private readonly IDbConnectionFactory _dbFactory;
public Func<IDbConnection, IDbConnection> ConnectionFilter { get; set; }
public FrontEndDbFactory(IDbConnectionFactory dbFactory, IAppSettings settings)
{
_dbFactory = dbFactory;
_settings = settings;
ConnectionFilter = (Func<IDbConnection, IDbConnection>)(x => x);
}
public IDbConnection OpenDbConnection()
{
var tenantId = Tenant.GetTenant();
return OpenTenant(tenantId);
}
public IDbConnection OpenTenant(string tenantId = null)
{
return tenantId != null
? new OrmLiteConnectionFactory(_settings.GetString("TenantId{0}:{1}".Fmt(tenantId, "Frontend"))).OpenDbConnection()
: _dbFactory.OpenDbConnection();
}
public IDbConnection CreateDbConnection()
{
return _dbFactory.CreateDbConnection();
}
}
IoC registration
IDbFrontEndConnectionFactory feFactory = new FrontEndDbFactory(masterDbFactory, fileSettings)
{
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
};
container.Register(feFactory);
Global.asax
protected void Application_Start(object sender, EventArgs e)
{
LogManager.LogFactory = new NLogFactory();
new AppHost().Init();
}
protected void Application_BeginRequest(object src, EventArgs e)
{
if (Request.IsLocal)
Profiler.Start();
}
protected void Application_EndRequest(object src, EventArgs e)
{
Profiler.Stop();
}
The Repository:
public partial class CampaignRepository : ICampaignRepository
{
readonly ILog _log = LogManager.GetLogger(typeof(CampaignRepository));
private readonly IDbFrontEndConnectionFactory _connectionFactory;
public CampaignRepository(IDbFrontEndConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
}
The IoC registration of my repository
container.Register<ICampaignRepository>(c => new CampaignRepository(c.Resolve<IDbFrontEndConnectionFactory>()));
The Service method when I'm inspecting the profiler
public CampaignViewModel Get(GetCampaign request)
{
if (request == null) throw new ArgumentNullException("request");
var profiler = Profiler.Current;
using (profiler.Step("Campaign Service Get"))
{
try
{
var vm = CampaignRepository.GetCampaignInfo(request.Id).ToViewModel();
if (vm.Campaign != null) return vm;
Response.StatusCode = (int)HttpStatusCode.NotFound;
return null;
}
catch (Exception exception)
{
_log.Error(request.ToJson(), exception);
throw;
}
}
}
I was expecting the profiler to show the sql timings, but that's not the case, the connection is not being profiled.
Is there something else that needs to be enabled or corrected for this to work?
Thank you, Stephen
To enable SQL Profiling in MiniProfiler you need to register the OrmLiteConnectionFactory to use MiniProfilers ProfiledDbConnection, e.g:
Container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
Related
I'm using Asp.Net Core Console Application and Entiy Framework Core and Unit of Work repository pattern. When I'm using multi thread function, I get this error:
DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
UnitOfwork.cs
public interface IUnitOfWork : IDisposable
{
void Commit();
ApplicationDbContext GetContext();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _applicationDbContext;
public UnitOfWork(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}
public void Commit()
{
try
{
_applicationDbContext.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public ApplicationDbContext GetContext()
{
return _applicationDbContext;
}
public void Dispose()
{
_applicationDbContext.Dispose();
}
}
IRepository.cs
public interface IGenericRepository<T>
where T : class, IEntity
{
List<T> GetAll(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
string includeProperties = "");
T FindSingle(int id);
T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "");
void Add(T toAdd);
void Update(T toUpdate);
void Delete(int id);
void Delete(T entity);
}
Repository.cs
public class GenericRepository<T> : IGenericRepository<T>
where T : class, IEntity
{
private readonly IUnitOfWork _unitOfWork;
public GenericRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public virtual List<T> GetAll(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
string includeProperties = "")
{
IQueryable<T> query = _unitOfWork.GetContext().Set<T>();
if (filter != null)
{
query = query.Where(filter);
}
foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
return query.ToList();
}
public virtual T FindSingle(int id)
{
return _unitOfWork.GetContext().Set<T>().Find(id);
}
public virtual T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "")
{
IQueryable<T> query = _unitOfWork.GetContext().Set<T>();
foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
return query.Where(predicate).FirstOrDefault();
}
public virtual void Add(T toAdd)
{
_unitOfWork.GetContext().Set<T>().Add(toAdd);
}
public virtual void Update(T toUpdate)
{
_unitOfWork.GetContext().Entry(toUpdate).State = EntityState.Modified;
}
public virtual void Delete(int id)
{
T entity = FindSingle(id);
_unitOfWork.GetContext().Set<T>().Remove(entity);
}
public virtual void Delete(T entity)
{
_unitOfWork.GetContext().Set<T>().Remove(entity);
}
}
Business Services;
public interface IUserService
{
void CreateUser(UserEntity userEntity, bool commit = false);
}
public class UserService : IUserService
{
private readonly IGenericRepository<UserEntity> _userRepository;
private readonly IUnitOfWork _unitOfWork;
public UserService(IUnitOfWork unitOfWork, IGenericRepository<UserEntity> userRepository)
{
_unitOfWork = unitOfWork;
_userRepository = userRepository;
}
public void CreateUser(UserEntity userEntity, bool commit = false)
{
try
{
_userRepository.Add(userEntity);
if (commit)
_unitOfWork.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console Main.cs;
class Program
{
public static ServiceProvider ServiceProvider;
static void Main(string[] args)
{
InitializeIoc();
Task.Run(() => { FuncA(); });
Task.Run(() => { FuncB(); });
Console.ReadLine();
}
private static void InitializeIoc()
{
ServiceProvider = new ServiceCollection()
.AddDbContext<ApplicationDbContext>()
.AddTransient<IUnitOfWork, UnitOfWork>()
.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>))
.AddTransient<IUserService, UserService>()
.BuildServiceProvider();
}
private static void FuncA()
{
var userService = ServiceProvider.GetService<IUserService>();
for (int i = 0; i < 100; i++)
{
userService.CreateUser(new UserEntity { FirstName = "FuncA_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
}
}
private static void FuncB()
{
var userService = ServiceProvider.GetService<IUserService>();
for (int i = 0; i < 100; i++)
{
userService.CreateUser(new UserEntity { FirstName = "FuncB_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
}
}
}
How can i solve this problem?
Thank you for your help.
The problem is that the used AddDbContext registers your ApplicationDbContext with ServiceLifetime.Scoped, but you are not creating scopes hence it effectively works as singleton, thus is shared and accessed concurrently by multiple threads which causes the exception in question (and potentially many other because DbContext is not thread safe).
The solution is to use scopes, e.g. call CreateScope and use returned object ServiceProvider property for resolving services:
private static void FuncA()
{
using (var scope = ServicePropvider.CreateScope())
{
var userService = scope.ServiceProvider.GetService<IUserService>();
// Do something ...
}
}
private static void FuncB()
{
using (var scope = ServicePropvider.CreateScope())
{
var userService = scope.ServiceProvider.GetService<IUserService>();
// Do something ...
}
}
I am converting xml to csv using spring batch and integration. I have a approach that job will start by reading files in from landing dir. while processing it will move files in inprocess dir. on error file will be moved to error dir. on successfully processing/writing file will be moved to output/completed.
After searching a while i got to know that there must be problem with itemreader but it is also returning null. I am not getting where is the problem.
Below is my batch configuration
#Bean
public Job commExportJob(Step parseStep) throws IOException {
return jobs.get("commExportJob")
.incrementer(new RunIdIncrementer())
.flow(parseStep)
.end()
.listener(listener())
.build();
}
#Bean
public Step streamStep() throws IOException {
CommReader itemReader = itemReader(null);
if (itemReader != null) {
return
steps.get("streamStep")
.<Object, Object>chunk(env.getProperty(Const.INPUT_READ_CHUNK_SIZE, Integer.class))
.reader(itemReader)
.processor(itemProcessor())
.writer(itemWriter(null))
.listener(getChunkListener())
.build();
}
return null;
}
#Bean
#StepScope
public ItemWriter<Object> itemWriter(#Value("#{jobParameters['outputFilePath']}") String outputFilePath) {
log.info("CommBatchConfiguration.itemWriter() : " + outputFilePath);
CommItemWriter writer = new CommItemWriter();
return writer;
}
#Bean
#StepScope
public CommReader itemReader(#Value("#{jobParameters['inputFilePath']}") String inputFilePath) {
log.info("CommBatchConfiguration.itemReader() : " + inputFilePath);
CommReader reader = new CommReader(inputFilePath);
// reader.setEncoding(env.getProperty("char.encoding","UTF-8"));
return reader;
}
#Bean
#StepScope
public CommItemProcessor itemProcessor() {
log.info("CommBatchConfiguration.itemProcessor() : Entry");
return new CommItemProcessor(ruleService);
}
CommReader.java
File inputFile = null;
private String jobName;
public CommReader(String inputFilePath) {
inputFile = new File(inputFilePath);
}
#Value("#{stepExecution}")
private StepExecution stepExecution;
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
#Override
public Object read() throws IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
if (inputFile.exists()) {
try {
builder = factory.newDocumentBuilder();
log.info("CommReader.read() :" + inputFile.getAbsolutePath());
Document document = builder.parse(inputFile);
return document;
} catch (ParserConfigurationException | SAXException | TransformerFactoryConfigurationError e) {
log.error("Exception while reading ", e);
}
}
return null;
}
#Override
public void close() throws ItemStreamException {
}
#Override
public void open(ExecutionContext arg0) throws ItemStreamException {
}
#Override
public void update(ExecutionContext arg0) throws ItemStreamException {
}
#Override
public void setResource(Resource arg0) {
}
CommItemProcessor.java
#Autowired
CommExportService ruleService;
public CommItemProcessor(CommExportService ruleService) {
this.ruleService = ruleService;
}
#Override
public Object process(Object bean) throws Exception {
log.info("CommItemProcessor.process() : Item Processor : " + bean);
return bean;
}
CommItemWriter.java
FlatFileItemWriter<byte[]> delegate;
ExecutionContext execContext;
FileOutputStream fileWrite;
File stylesheet;
StreamSource stylesource;
Transformer transformer;
List<List<?>> itemsTotal = null;
int recordCount = 0;
#Autowired
FileUtil fileUtil;
#Value("${input.completed.dir}")
String completedDir;
#Value("${input.inprocess.dir}")
String inprocessDir;
public void update(ExecutionContext arg0) throws ItemStreamException {
this.delegate.update(arg0);
}
public void open(ExecutionContext arg0) throws ItemStreamException {
this.execContext = arg0;
this.delegate.open(arg0);
}
public void close() throws ItemStreamException {
this.delegate.close();
}
#Override
public void write(List<? extends Object> items) throws Exception {
log.info("CommItemWriter.write() : items.size() : " + items.size());
stylesheet = new File("./config/style.xsl");
stylesource = new StreamSource(stylesheet);
String fileName = fileUtil.getFileName();
try {
transformer = TransformerFactory.newInstance().newTransformer(stylesource);
} catch (TransformerConfigurationException | TransformerFactoryConfigurationError e) {
log.error("Exception while writing",e);
}
for (Object object : items) {
log.info("CommItemWriter.write() : Object : " + object.getClass().getName());
log.info("CommItemWriter.write() : FileName : " + fileName);
Source source = new DOMSource((Document) object);
Result outputTarget = new StreamResult(
new File(fileName));
transformer.transform(source, outputTarget);
}
}
In chunkListener there is nothing much i am doing.
Below is the job listener.
#Override
public void beforeJob(JobExecution jobExecution) {
log.info("JK: CommJobListener.beforeJob()");
}
#Override
public void afterJob(JobExecution jobExecution) {
log.info("JK: CommJobListener.afterJob()");
JobParameters jobParams = jobExecution.getJobParameters();
File inputFile = new File(jobParams.getString("inputFilePath"));
File outputFile = new File(jobParams.getString("outputFilePath"));
try {
if (jobExecution.getStatus().isUnsuccessful()) {
Files.move(inputFile.toPath(), Paths.get(inputErrorDir, inputFile.getName()),
StandardCopyOption.REPLACE_EXISTING);
Files.move(outputFile.toPath(), Paths.get(outputErrorDir, outputFile.getName()),
StandardCopyOption.REPLACE_EXISTING);
} else {
String inputFileName = inputFile.getName();
Files.move(inputFile.toPath(), Paths.get(inputCompletedDir, inputFileName),
StandardCopyOption.REPLACE_EXISTING);
Files.move(outputFile.toPath(), Paths.get(outputCompletedDir, outputFile.getName()),
StandardCopyOption.REPLACE_EXISTING);
}
} catch (IOException ioe) {
log.error("IOException occured ",ioe);
}
}
I am also using integration flow.
#Bean
public IntegrationFlow messagesFlow(JobLauncher jobLauncher) {
try {
Map<String, Object> headers = new HashMap<>();
headers.put("jobName", "commExportJob");
return IntegrationFlows
.from(Files.inboundAdapter(new File(env.getProperty(Const.INPUT_LANDING_DIR)))
,
e -> e.poller(Pollers
.fixedDelay(env.getProperty(Const.INPUT_POLLER_DELAY, Integer.class).intValue())
.maxMessagesPerPoll(
env.getProperty(Const.INPUT_MAX_MESSAGES_PER_POLL, Integer.class).intValue())
.taskExecutor(getFileProcessExecutor())))
.handle("moveFile","moveFile")
.enrichHeaders(headers)
.transform(jobTransformer)
.handle(jobLaunchingGw(jobLauncher))
.channel("nullChannel").get();
} catch (Exception e) {
log.error("Exception in Integration flow",e);
}
return null;
}
#Autowired
private Environment env;
#Bean
public MessageHandler jobLaunchingGw(JobLauncher jobLauncher) {
return new JobLaunchingGateway(jobLauncher);
}
#MessagingGateway
public interface IMoveFile {
#Gateway(requestChannel = "moveFileChannel")
Message<File> moveFile(Message<File> inputFileMessage);
}
#Bean(name = "fileProcessExecutor")
public Executor getFileProcessExecutor() {
ThreadPoolTaskExecutor fileProcessExecutor = new ThreadPoolTaskExecutor();
fileProcessExecutor.setCorePoolSize(env.getRequiredProperty(Const.INPUT_EXECUTOR_POOLSIZE, Integer.class));
fileProcessExecutor.setMaxPoolSize(env.getRequiredProperty(Const.INPUT_EXECUTOR_MAXPOOLSIZE, Integer.class));
fileProcessExecutor.setQueueCapacity(env.getRequiredProperty(Const.INPUT_EXECUTOR_QUEUECAPACITY, Integer.class));
fileProcessExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
fileProcessExecutor.initialize();
return fileProcessExecutor;
}
Try to return document itself instead of Object in read method of CommReader.java and then check whether its coming null or not in the writer to stop it.
I'm having a problems configuring instance per http request in service stack. I am running a console app and trying to use Ninject as my container.
I would like an instance to last for 1 full request. I would like to know how I can configure this.
I would like an example showing how I could start the lifetime of the dependency when the request starts and how to dispose that same instance when the request ends.
Could anyone give me an example of how to do this in autofac and ninject.
public class OutboundHost : AppHostHttpListenerBase
{
public OutboundHost() : base("StarterTemplate HttpListener", typeof(SmsService).Assembly) { }
protected override void ProcessRequest(System.Net.HttpListenerContext context)
{
Console.WriteLine("Begin Processing request");
base.ProcessRequest(context);
}
public override void Start(string urlBase)
{
base.Start(urlBase);
}
public override void OnEndRequest()
{
Console.WriteLine("End processing request");
base.OnEndRequest();
}
public override void Configure(Funq.Container container) {
IKernel kernel = new StandardKernel();
RegisterEntityFrameworkNinject(kernel);
RegisterDependenciesNinject(kernel);
LogManager.LogFactory = new ConsoleLogFactory();
Console.WriteLine("Starting Container");
container.Register<ICacheClient>(new MemoryCacheClient());
container.RegisterValidators(typeof(SendSmsValidator).Assembly);
Plugins.Add(new RazorFormat());
Plugins.Add(new ValidationFeature());
Plugins.Add(new RequestLogsFeature() { RequiredRoles = new string[] { } });
Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {new CustomCredentialsAuthProvider(), }));
SetConfig(new EndpointHostConfig
{
CustomHttpHandlers = {
{ System.Net.HttpStatusCode.NotFound, new RazorHandler("/notfound") }
}
});
InitializeLookupTables(kernel);
container.Adapter = new NinjectIocAdapter(kernel);
}
private void RegisterDependenciesNinject(IKernel kernel)
{
kernel.Bind<ILog>().ToMethod(c => LogManager.LogFactory.GetLogger(typeof (ConsoleLogger))).InSingletonScope();
kernel.Bind<ISendSmsIntenda>().To<SendSmsIntenda>();
}
private void RegisterEntityFrameworkNinject(IKernel kernel)
{
kernel.Bind<IEntityFrameworkUnitOfWork>().To<EntityFrameworkUnitOfWork>();
kernel.Bind<IUnitOfWork>().To<EntityFrameworkUnitOfWork>();
kernel.Bind<IRepository>().To<Repository>();
kernel.Bind<ILookupTableFactory>().To<EntityFrameworkLookupTableFactory>();
kernel.Bind<IDataQuery>().To<DatabaseQuery>();
kernel.Bind<IContextFactory>().To<DefaultContextFactory<OutboundContext>>().InSingletonScope()
.WithConstructorArgument("connectionStringName", GetConnectionString());
}
private string GetConnectionString()
{
return ConfigurationManager.ConnectionStrings["Outbound"].ConnectionString;
}
private void InitializeLookupTables(IKernel kernel)
{
using (var kernelContext = kernel.BeginBlock())
{
var contextFactory = kernelContext.Get<IContextFactory>();
var frameworkContext = kernelContext.Get<IContextFactory>().GetContext() as IFrameworkContext;
var unitOfWork = kernelContext.Get<IUnitOfWork>();
contextFactory.GetContext().RegisterLookupTable<SmsStatusType, SmsStatusEnum>();
frameworkContext.SaveLookupTableChanges();
unitOfWork.Commit();
}
}
}
public class NinjectIocAdapter : IContainerAdapter
{
private readonly IKernel kernel;
private readonly Container container;
public NinjectIocAdapter(IKernel kernel, Funq.Container container)
{
this.kernel = kernel;
this.container = container;
}
public T Resolve<T>()
{
return this.kernel.Get<T>();
}
public T TryResolve<T>()
{
return this.kernel.TryGet<T>();
}
}
I have this base class structure:
Base:
public abstract class BackgroundTask
{
protected readonly Logger Logger = LogManager.GetCurrentClassLogger();
protected virtual void Initialize()
{
// initialize database access
}
public void Run()
{
Initialize();
try
{
Execute();
// insert to database or whatever
}
catch (Exception ex)
{
Logger.ErrorException(string.Format("Error proccesing task: {0}\r\n", ToString()), ex);
Exceptions.Add(ex);
}
finally
{
TaskExecuter.Discard();
}
}
protected abstract void Execute();
public abstract override string ToString();
public IList<Exception> Exceptions = new List<Exception>();
}
Task executor:
public static class TaskExecuter
{
private static readonly ThreadLocal<IList<BackgroundTask>> TasksToExecute
= new ThreadLocal<IList<BackgroundTask>>(() => new List<BackgroundTask>());
public static void ExecuteLater(BackgroundTask task)
{
TasksToExecute.Value.Add(task);
}
public static void StartExecuting()
{
foreach (var backgroundTask in TasksToExecute.Value)
{
Task.Factory.StartNew(backgroundTask.Run);
}
}
public static void Discard()
{
TasksToExecute.Value.Clear();
TasksToExecute.Dispose();
}
}
FileTask:
public class FileTask : BackgroundTask
{
protected static string BaseFolder = #"C:\ASCII\";
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
private readonly string _folder;
private IHistoryRepository _historyRepository;
public string Folder
{
get { return _folder; }
}
public FileTask(string folder)
{
_folder = string.Format("{0}{1}", BaseFolder, folder);
}
protected override void Initialize()
{
_historyRepository = new HistoryRepository();
}
protected override void Execute()
{
// todo: Get institute that are active,
var institute = MockInstitute(); // todo: uncomment _historyRepository.FindInstituteByFolderName(Folder);
// todo: Update institute, lastupdate - [date] | [files amount] | [phonenumbers amount]
if (institute == null)
{
Logger.Warn("Not found data", Folder);
return;
}
// todo: read file get encoding | type and parse it
Task.Factory.StartNew(ReadFile);
}
private void ReadFile()
{
var list = GetFilesByFolder();
StreamReader sr = null;
try
{
Lock.EnterReadLock();
foreach (var fi in list)
{
var fileName = fi.FullName;
Logger.Info("Line: {0}:=> Content: {1}", fileName, Thread.CurrentThread.ManagedThreadId);
sr = new StreamReader(fileName, DetectEncoding(fileName));
string currentLine;
while ((currentLine = sr.ReadLine()).ReturnSuccess())
{
if (string.IsNullOrEmpty(currentLine)) continue;
Logger.Info("Line: {0}:=> Content: {1}", fileName, currentLine);
}
}
Lock.ExitReadLock();
}
finally
{
if (sr != null) sr.Dispose();
Logger.Info("Finished working" + Folder);
}
}
protected IEnumerable<FileInfo> GetFilesByFolder()
{
return Directory.GetFiles(Folder).Select(fileName => new FileInfo(fileName));
}
protected Encoding DetectEncoding(string file)
{
using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
var cdet = new Ude.CharsetDetector();
cdet.Feed(fs);
cdet.DataEnd();
return cdet.With(x => x.Charset)
.Return(x => Encoding.GetEncoding(cdet.Charset),
Encoding.GetEncoding("windows-1255"));
}
}
private Institute MockInstitute()
{
return new Institute
{
FromFolderLocation = string.Format("{0}{1}", BaseFolder, Folder)
};
}
public override string ToString()
{
return string.Format("Folder: {0}", Folder);
}
}
When don't read the file every thing ok, the Log is populated and every thing runs smooth,
but when i attach the Task.Factory.StartNew(ReadFile); method i have an exception.
Exception:
Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'.
How do i solve that issue? might i need to change the LocalThread logic, or what - i have been trying to handle that issue, for almost a day.
BTW: It's an MVC4 project, and C# 5.0 and i'm trying to TDD it all.
You shouldn't be calling TasksToExecute.Dispose();
there.
Here is my problem:
I want to pass in one of the values to the constructor every time I request an instance form the kernel. I written some code below to illustrate the problem. The test is not failing so I guess that this works, but it does look pretty ugly. Is there a better, cleaner way to accomplish this with Ninject? Or should I rethink my design? All suggestions are appreciated.
[TestFixture]
public class Sandbox
{
[Test]
public void Run_Forrest_Run()
{
using (var kernel = new StandardKernel(new Module()))
{
var connection = new Connection(Guid.NewGuid().ToString());
var downloader = kernel.Get<IDownloader>(new IParameter[] { new Parameter("connection", connection, false) });
Assert.That(downloader.Connection.Info, Is.EqualTo(connection.Info));
}
}
public class Downloader : IDownloader
{
public Downloader(Connection connection, ILogger logger)
{
Connection = connection;
Logger = logger;
}
public Connection Connection { get; private set; }
public void Download()
{
Logger.Log("Downloading...");
}
public ILogger Logger { get; private set; }
}
public interface IDownloader
{
Connection Connection { get; }
void Download();
}
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.Out.WriteLine(message);
}
}
public interface ILogger
{
void Log(string message);
}
public class Connection
{
public Connection(string info)
{
Info = info;
}
public string Info { get; private set; }
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<ConsoleLogger>();
Bind<IDownloader>().To<Downloader>()
.WithConstructorArgument("connection", context =>
{
var p = context.Parameters.First(x => x.Name == "connection");
return p.GetValue(context, null);
});
}
}
}
If you always want to specify the Connection when resolving a IDownloader then I think the ConstructorArgument (which is a IParameter) is what you are looking for:
[Test]
public void Run_Forrest_Run()
{
using (var kernel = new StandardKernel(new Module()))
{
var connection = new Connection(Guid.NewGuid().ToString());
var downloader = kernel.Get<IDownloader>(new [] {
new ConstructorArgument("connection", connection) });
Assert.That(downloader.Connection.Info, Is.EqualTo(connection.Info));
}
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<ILogger>().To<ConsoleLogger>();
Bind<IDownloader>().To<Downloader>();
}
}