Castle Windsor Singleton Instantiated On Each Call To Resolve - castle-windsor

I'm using Castle Windsor 2.5.3 in an ASP.NET 4.0 Web Application (not ASP.NET MVC)
I have an interceptor which is being used to intercept calls to a data access component. The interceptor depends on a cache manager. The cache manager is used by the interceptor to avoid calling the data access component if the cache manager has the required data.
Even though the cache manager is registered as a Singleton, it is being instantiated multiple times. I can prove this with a debug message or a hit-count breakpoint in its default constructor.
A new requirement is for the cache to be clearable on demand, so I thought it would be a simple matter of resolving the Cache Manager and calling EmptyCache. What is happening is that the container is creating a new instance of the Cache Manager on which the call to EmptyCache has no effect (since the new cache manager has no cached data). Here is the code in the web page for clearing the cache:
protected void flushButton_Click(object sender, EventArgs e)
{
ICacheManager cacheManager = null;
try
{
cacheManager = Global.Container.Resolve<ICacheManager>();
cacheManager.EmptyCache();
resultLabel.Text = "Cache has been flushed";
}
catch (Exception ex)
{
resultLabel.Text = "An error occurred. The reason given was: " + ex.Message;
}
finally
{
if (cacheManager != null)
Global.Container.Release(cacheManager);
}
}
When I hover over the Container in Visual Studio and drill into the Components, the CacheManager is marked as Singleton. How can this be happening?
My Cache Manager is registered like this:
public class WindsorComponentInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(typeof(Data.Common.Cache.ICacheManager))
.ImplementedBy(typeof(Data.Common.Cache.CacheManager))
.LifeStyle.Singleton
);
container.Register(
Component.For<Data.Common.CachingInterceptor>()
);
}
}
The Cache Manager interface looks like this:
public interface ICacheManager
{
object CacheItem(string cacheKey, DateTime absoluteExpiration, CacheItemPriority priority, Func<object> itemProvider);
object CacheItem(string cacheKey, TimeSpan slidingExpiration, CacheItemPriority priority, Func<object> itemProvider);
void EmptyCache();
}
The interceptor looks like this:
public class CachingInterceptor : IInterceptor
{
private ILogger logger = NullLogger.Instance;
private ICacheManager cacheManager;
public CachingInterceptor(ICacheManager cacheManager)
{
this.cacheManager = cacheManager;
}
public ILogger Logger
{
set
{
if (value != null) logger = value;
}
}
public void Intercept(IInvocation invocation)
{
try
{
string cacheItemKey = MakeCacheItemKey(invocation);
//Debug.WriteLine("Cache Key: {0}", cacheItemKey);
TimeSpan lifespan = TimeSpan.Parse("00:20:00");
bool cacheHit = true;
object result = cacheManager.CacheItem(cacheItemKey, lifespan, CacheItemPriority.Low,
() =>
{
invocation.Proceed();
//Debug.WriteLine(String.Format("populate-the-cache callback was invoked and returned a {0}", invocation.ReturnValue ?? "null"));
cacheHit = false;
return invocation.ReturnValue;
}
);
logger.DebugFormat("Interceptor {0} Cache Hit: {1}", (invocation.Method.Name ?? "null"), cacheHit.ToString());
invocation.ReturnValue = result;
}
catch (Exception ex)
{
logger.Error("Intercept Error", ex);
}
}
private string MakeCacheItemKey(IInvocation invocation)
{
StringBuilder sb = new StringBuilder();
sb.Append(invocation.InvocationTarget);
sb.Append("|" + invocation.MethodInvocationTarget.Name);
sb.Append("|" + invocation.MethodInvocationTarget.ReturnType);
foreach (ParameterInfo pi in invocation.MethodInvocationTarget.GetParameters())
sb.Append("|" + pi.ParameterType.ToString());
foreach (var arg in invocation.Arguments)
{
sb.Append("|");
sb.Append(arg ?? "null");
}
return sb.ToString();
}
}
The data components are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
string connStr = ConfigurationManager.ConnectionStrings["Database"].ConnectionString;
container.Register(
Component.For<IActualCostsVersusBudgetDataProvider>()
.ImplementedBy<ActualCostsVersusBudgetDataProvider>()
.DependsOn(Property.ForKey("connectionString").Eq(connStr))
.LifeStyle.Transient
.Interceptors(InterceptorReference.ForType<CachingInterceptor>())
.Anywhere
);
/* Many calls to .Register omitted */
}
The business objects that depend on data providers are registered like this:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
AllTypes.FromThisAssembly()
.Where(t => t.Name.EndsWith("Manager"))
.Configure(c => c.LifeStyle.Transient)
);
}
The container is initialized like this in global.asax:
public static IWindsorContainer Container { get; private set; }
public Global()
{
Container = BootstrapContainer();
}
private IWindsorContainer BootstrapContainer()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<LoggingFacility>(f => f.LogUsing(LoggerImplementation.Log4net).WithAppConfig());
container.Install(
new Data.Common.Installers.WindsorComponentInstaller(),
new Data.Installers.WindsorComponentInstaller(),
new Business.Installers.WindsorComponentInstaller()
);
return container;
}

Related

Nested Transactions with MySQL and Entity Framework Core

I'm using MySQL with EF Core. I am currently using Pomelo Provider for MySQL. I need to implement Unit Of Work Pattern for transactions. I have a Service which calls two methods in repository. I am not able to implement nested transactions. This is how my method in service looks now:
public void methodA(param)
{
using (TransactionScope tx = new
TransactionScope(TransactionScopeOption.Required))
{
repo1.save(data1);
repo2.save(data2);
tx.complete();
}
}
This is how save method in repo1 is implemented
private readonly UserDbContext appDbContext;
public repo1(UserDbContext _appDbContext)
{
appDbContext = _appDbContext;
}
public void save(User entity)
{
var dbset = appDbContext.Set<User>().Add(entity);
appDbContext.SaveChanges();
}
This is how save method in repo2 is implemented
private readonly UserDbContext appDbContext;
public repo2(UserDbContext _appDbContext)
{
appDbContext = _appDbContext;
}
public void save(UserRole entity)
{
var dbset = appDbContext.Set<UserRole>().Add(entity);
appDbContext.SaveChanges();
}
I am getting the following error while running method in service:
Error generated for warning 'Microsoft.EntityFrameworkCore.Database.Transaction.AmbientTransactionWarning: An ambient transaction has been detected. The current provider does not support ambient transactions. See http://go.microsoft.com/fwlink/?LinkId=800142'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.AmbientTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.
This is how I registered UserDbContext in Startup.cs
services.AddDbContext<UserDbContext>(options => options.UseLazyLoadingProxies().UseMySql("Server = xxxx; Database = xxx; Uid = xx;ConnectionReset=True;", b => b.MigrationsAssembly("AssemblyName")));
I even tried adding a middleware which starts transaction at the begining of request and commits/rollbacks during the response . But still I am not able to manage nested transactions.
This is how my middleware looks:
public class TransactionPerRequestMiddleware
{
private readonly RequestDelegate next_;
public TransactionPerRequestMiddleware(RequestDelegate next)
{
next_ = next;
}
public async Task Invoke(HttpContext context, UserDbContext
userDbContext)
{
var transaction = userDbContext.Database.BeginTransaction(
System.Data.IsolationLevel.ReadCommitted);
await next_.Invoke(context);
int statusCode = context.Response.StatusCode;
if (statusCode == 200 || statusCode==302)
{
transaction.Commit();
}
else
{
transaction.Rollback();
}
}
}
Can anyone help me please?

How to inject services in a controller inside a reusable Razor Class Library

I am using a Razor Class Library for making a reusable complex View (which includes its controller and several View Components) that can be used across several ASP.NET Core MVC projects. The problem is that the controller use dependency injection (a custom service called "GatewayProxy" and string localization). What is the correct way to inject services into a controller inside a RCL?
Here is the structure of my RCL:
Here is the exception:
You mentioned how you fixed this by adding the dependencies to Startup.cs of your main project. But consider that any consumer of this reuseable library may not remember (or know) what dependencies are needed for your library.
Something you can do to solve this is to create an extension off of IServiceCollection in your Rcl that does the dependency registration.
public static void AddMyRclServices(this IServiceCollection serviceCollection, IConfiguration config)
{
serviceCollection.AddTransient<IRclService1, RclService1>();
serviceCollection.AddScoped<IRclService2, RclService2>();
}
Then in Startup.cs for your MVC project call the extension
using Rcl.Extensions
public void ConfigureServices(IServiceCollection services)
{
services.AddMyRclServices(config);
}
You can inject from load assemblies.
my code
ISturtupInitializers.cs
public interface ISturtupInitializers {
void Compose(IServiceCollection serviceCollection);
}
TypeLoader.cs
public static readonly Lazy<HashSet<Assembly>> AllAssemblies = new Lazy<HashSet<Assembly>>(() => {
var bin_folder = Assembly.GetExecutingAssembly().GetFileInfo().Directory.FullName;
var bin_assembly_files = Directory.GetFiles(bin_folder, "*.dll", SearchOption.TopDirectoryOnly).Where(x => !SystemAssemblies.Any(xs => x.IndexOf(xs, StringComparison.CurrentCultureIgnoreCase) >= 0)).ToList();
var assemblies = new HashSet<Assembly>();
foreach (var a in bin_assembly_files)
{
try {
var assName = AssemblyName.GetAssemblyName(a);
var ass = Assembly.Load(assName);
assemblies.Add(ass);
} catch (SecurityException e) {
//ignore
} catch (FileNotFoundException e) {
//ignore
} catch (BadImageFormatException e) {
//ignore
}
catch (Exception e) {
throw;
}
}
return assemblies;
});
public static string[] SystemAssemblies = new[] {
"Microsoft.",
"System.",
"Newtonsoft."
};
public static FileInfo GetFileInfo(this Assembly assembly)
{
var uri = new Uri(assembly.CodeBase);
var path = uri.LocalPath;
return new FileInfo(path);
}
Composer.cs
public class Composer {
private static readonly Lazy<HashSet<Type>> _sturtup_initializers = new Lazy<HashSet<Type>>(() => {
var aseemblies = TypeLoader.AllAssemblies.Value.SelectMany(x=>GetAllTypesInAssembly(x, typeof(ISturtupInitializers)));
var result = new HashSet<Type>();
foreach (var item in aseemblies) {
result.Add(item);
}
return result;
});
public static void Compose(IServiceCollection services) {
var composers = _sturtup_initializers.Value;
foreach (var compose in composers) {
public static void Compose(IServiceCollection services, IConfiguration configuration) {
var composers = _sturtup_initializers.Value;
var provider = services.BuildServiceProvider();
foreach (var compose in composers) {
((IStartupInitializers) ActivatorUtilities.CreateInstance(provider, compose)).Compose(services, configuration);
}
}
}
}
private static IEnumerable<Type> GetAllTypesInAssembly(Assembly assembly, Type implementInterface) {
var types = assembly.GetTypes();
return types.Where(x => x.GetInterfaces().Any(i => i == implementInterface));
}
}
MyStartup.cs
public class ServiceCollectionExtensions : ISturtupInitializers
{
public void Compose(IServiceCollection serviceCollection) {
/** YOUR CODE **/
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services) {
/** YOUR CODE **/
Composer.Compose(services);
}

ViewPart hangs on click of JButton

I am working on Teamcenter RAC customization. I have changed an existing code which deals with viewpart and jbuttons on it. The viewpart(SWT) loads a stylesheet rendering panel. the problem is whenever I click on the save button (JButton) this hangs the teamcenter application on post -executing activities.
The code is as follows:
saveCheckOutButton.addActionListener( new ActionListener()
{
#Override
public void actionPerformed( ActionEvent paramAnonymousActionEvent )
{
final AbstractRendering sheetPanel = itemPanel.getStyleSheetPanel();
final AbstractRendering sheetPanel1 = itemRevPanel.getStyleSheetPanel();
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground()
throws Exception
{
if(pPanel==null)
return null;
if( pPanel.isPanelSavable())
{
if(sheetPanel==null|| sheetPanel1==null)
return null;
sheetPanel.saveRendering();
sheetPanel1.saveRendering();
/*if(!sheetPanel.getErrorFlag() && !sheetPanel1.getErrorFlag())
{
sheetPanel.setModifiable( false );
sheetPanel1.setModifiable( false );
}*/
}
return null;
}
#Override
protected void done(){
if(!sheetPanel.getErrorFlag() && !sheetPanel1.getErrorFlag())
{
sheetPanel.setModifiable( false );
sheetPanel1.setModifiable( false );
}
}
};
worker.execute();
}
} );
I have written the code under swingworker as suggested by some of the experts here but to no success. Request for some immediate help.
What do you mean by "it hangs the teamcenter application". Whether it responds too slow or doInBackground() is not properly executed?
Anyway you can try executing your rendering code in SwingUtilities.invokeLater() and use the method get(). If you don't call get() in the done method, you will lose all the exceptions that the computation in the doInBackground() has thrown. So we will get to know about exception if any is there.
SwingUtilities.invokeLater() allows a task to be executed at some later point in time, as the name suggests; but more importantly, the task will be executed on the AWT event dispatch thread. Refer Invoke later API documentation for the detailed info.
About get():
Waits if necessary for the computation to complete, and then retrieves its result.
Note: calling get on the Event Dispatch Thread blocks all events, including repaints, from being processed until this SwingWorker is complete.
saveCheckOutButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent paramAnonymousActionEvent) {
final AbstractRendering sheetPanel = itemPanel.getStyleSheetPanel();
final AbstractRendering sheetPanel1 = itemRevPanel.getStyleSheetPanel();
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
if (pPanel == null)
return null;
if (pPanel.isPanelSavable()) {
if (sheetPanel == null || sheetPanel1 == null)
return null;
saveRendering();
}
return null;
}
#Override
protected void done() {
try {
get();
if (!sheetPanel.getErrorFlag() && !sheetPanel1.getErrorFlag()) {
sheetPanel.setModifiable(false);
sheetPanel1.setModifiable(false);
}
} catch (final InterruptedException ex) {
throw new RuntimeException(ex);
} catch (final ExecutionException ex) {
throw new RuntimeException(ex.getCause());
}
}
};
worker.execute();
}
});
private void saveRendering() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
sheetPanel.saveRendering();
sheetPanel1.saveRendering();
}
});
}

WcfFacility and Sequence contains no elements error?

I have wcf library with service contracts and implementations.
[ServiceContract]
public interface IServiceProtoType
{
[OperationContract]
Response GetMessage(Request request);
[OperationContract]
String SayHello();
}
[DataContract]
public class Request
{
private string name;
[DataMember]
public string Name
{
get { return name; }
set { name = value; }
}
}
[DataContract]
public class Response
{
private string message;
[DataMember]
public string Message
{
get { return message; }
set { message = value; }
}
}
public class MyDemoService : IServiceProtoType
{
public Response GetMessage(Request request)
{
var response = new Response();
if (null == request)
{
response.Message = "Error!";
}
else
{
response.Message = "Hello, " + request.Name;
}
return response;
}
public string SayHello()
{
return "Hello, World!";
}
}
I have windows service project that references this library, where MyService is just an empty shell that inherits ServiceBase. This service is installed and running under local system.
static void Main()
{
ServiceBase.Run(CreateContainer().Resolve());
}
private static IWindsorContainer CreateContainer()
{
IWindsorContainer container = new WindsorContainer();
container.Install(FromAssembly.This());
return container;
}
public class ServiceInstaller : IWindsorInstaller
{
#region IWindsorInstaller Members
public void Install(IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
string myDir;
if (string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath))
{
myDir = AppDomain.CurrentDomain.BaseDirectory;
}
else
{
myDir = AppDomain.CurrentDomain.RelativeSearchPath;
}
var wcfLibPath = Path.Combine(myDir , "WcfDemo.dll");
string baseUrl = "http://localhost:8731/DemoService/{0}";
AssemblyName myAssembly = AssemblyName.GetAssemblyName(wcfLibPath);
container
.Register(
AllTypes
.FromAssemblyNamed(myAssembly.Name)
.InSameNamespaceAs<WcfDemo.MyDemoService>()
.WithServiceDefaultInterfaces()
.Configure(c =>
c.Named(c.Implementation.Name)
.AsWcfService(
new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Implementation.Name)
)))), Component.For<ServiceBase>().ImplementedBy<MyService>());
}
#endregion
}
In Client Console app I have the following code and I am getting the following error:
{"Sequence contains no elements"}
static void Main(string[] args)
{
IWindsorContainer container = new WindsorContainer();
string baseUrl = "http://localhost:8731/DemoService/{0}";
container.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero);
container
.Register(
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
.Configure(
c => c.Named(c.Implementation.Name)
.AsWcfClient(new DefaultClientModel
{
Endpoint = WcfEndpoint
.BoundTo(new WSHttpBinding())
.At(string.Format(baseUrl,
c.Name.Substring(1)))
})));
var service1 = container.Resolve<IServiceProtoType>();
Console.WriteLine(service1.SayHello());
Console.ReadLine();
}
I have an idea what this may be but you can stop reading this now (and I apologize for wasting your time in advance) if the answer to the following is no:
Is one (or more) of Request, Response, or MyDemoService in the same namespace as IServiceProtoType?
I suspect that Windsor is getting confused about those, since you are doing...
Types
.FromAssemblyContaining<IServiceProtoType>()
.InSameNamespaceAs<IServiceProtoType>()
... and then configuring everything which that returns as a WCF client proxy. This means that it will be trying to create proxies for things that should not be and hence a Sequence Contains no Elements exception (not the most useful message IMHO but crushing on).
The simple fix would be just to put your IServiceProtoType into its own namespace (I often have a namespace like XXXX.Services for my service contracts).
If that is not acceptable to you then you need to work out another way to identify just the service contracts - take a look at the If method for example or just a good ol' Component.For perhaps.

Ehcache hangs in test

I am in the process of rewriting a bottle neck in the code of the project I am on, and in doing so I am creating a top level item that contains a self populating Ehcache. I am attempting to write a test to make sure that the basic call chain is established, but when the test executes it hands when retrieving the item from the cache.
Here are the Setup and the test, for reference mocking is being done with Mockito:
#Before
public void SetUp()
{
testCache = new Cache(getTestCacheConfiguration());
recordingFactory = new EntryCreationRecordingCache();
service = new Service<Request, Response>(testCache, recordingFactory);
}
#Test
public void retrievesResultsFromSuppliedCache()
{
ResultType resultType = mock(ResultType.class);
Response expectedResponse = mock(Response.class);
addToExpectedResults(resultType, expectedResponse);
Request request = mock(Request.class);
when(request.getResultType()).thenReturn(resultType);
assertThat(service.getResponse(request), sameInstance(expectedResponse));
assertTrue(recordingFactory.requestList.contains(request));
}
private void addToExpectedResults(ResultType resultType,
Response response) {
recordingFactory.responseMap.put(resultType, response);
}
private CacheConfiguration getTestCacheConfiguration() {
CacheConfiguration cacheConfiguration = new CacheConfiguration("TEST_CACHE", 10);
cacheConfiguration.setLoggingEnabled(false);
return cacheConfiguration;
}
private class EntryCreationRecordingCache extends ResponseFactory{
public final Map<ResultType, Response> responseMap = new ConcurrentHashMap<ResultType, Response>();
public final List<Request> requestList = new ArrayList<Request>();
#Override
protected Map<ResultType, Response> generateResponse(Request request) {
requestList.add(request);
return responseMap;
}
}
Here is the ServiceClass
public class Service<K extends Request, V extends Response> {
private Ehcache cache;
public Service(Ehcache cache, ResponseFactory factory) {
this.cache = new SelfPopulatingCache(cache, factory);
}
#SuppressWarnings("unchecked")
public V getResponse(K request)
{
ResultType resultType = request.getResultType();
Element cacheEntry = cache.get(request);
V response = null;
if(cacheEntry != null){
Map<ResultType, Response> resultTypeMap = (Map<ResultType, Response>) cacheEntry.getValue();
try{
response = (V) resultTypeMap.get(resultType);
}catch(NullPointerException e){
throw new RuntimeException("Result type not found for Result Type: " + resultType);
}catch(ClassCastException e){
throw new RuntimeException("Incorrect Response Type for Result Type: " + resultType);
}
}
return response;
}
}
And here is the ResponseFactory:
public abstract class ResponseFactory implements CacheEntryFactory{
#Override
public final Object createEntry(Object request) throws Exception {
return generateResponse((Request)request);
}
protected abstract Map<ResultType,Response> generateResponse(Request request);
}
After wrestling with it for a while, I discovered that the cache wasn't being initialized. Creating a CacheManager and adding the cache to it resolved the problem.
I also had a problem with EHCache hanging, although only in a hello-world example. Adding this to the end fixed it (the application ends normally).
CacheManager.getInstance().removeAllCaches();
https://stackoverflow.com/a/20731502/2736496