I'm trying to create an MvxTabsFragmentActivity and bind a button on a fragment to a command. The problem I'm getting is the following error.
MvxBind:Warning: 7.94 Failed to create target binding for binding Command for SignInCommand
[0:] MvxBind:Warning: 7.94 Failed to create target binding for binding Command for SignInCommand
04-01 00:40:53.062 I/mono-stdout( 5079): MvxBind:Warning: 7.94 Failed to create target binding for binding Command for SignInCommand
04-01 00:40:53.082 D/Mono ( 5079): Remapped public key token of retargetable assembly System from 7cec85d7bea7798e to b77a5c561934e089
04-01 00:40:53.082 D/Mono ( 5079): The request to load the retargetable assembly System v2.0.5.0 was remapped to System v2.0.0.0
04-01 00:40:53.092 D/Mono ( 5079): Unloading image System.dll [0x7f041ff0].
04-01 00:40:53.092 D/Mono ( 5079): Image addref System[0x7f04b030] -> System.dll[0x79befc10]: 16
[0:]
04-01 00:40:53.092 D/Mono ( 5079): Assembly Ref addref Cirrious.CrossCore[0x753c1000] -> System[0x79be85c0]: 15
MvxBind:Warning: 7.99 Failed to create target binding for binding CommandParameter for .
[0:] MvxBind:Warning: 7.99 Failed to create target binding for binding CommandParameter for .
04-01 00:40:53.112 I/mono-stdout( 5079): MvxBind:Warning: 7.99 Failed to create target binding for binding CommandParameter for .
My fragments are drawn exactly right, but the MvxBind isn't binding.
Here's the axml
<Button
android:id="#+id/RegisterFragment_SignInButton"
android:layout_below="#id/SignInFragment_Password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/signin_text"
local:MvxBind="Command SignInCommand; CommandParameter ." />
Here's my Activity
public class AuthView : MvxTabsFragmentActivity
{
private new AuthViewModel ViewModel { get { return (AuthViewModel)base.ViewModel; } }
public AuthView() : base(Resource.Layout.AuthView, Resource.Id.actualtabcontent)
{
}
protected override void AddTabs(Bundle args)
{
AddTab<SignInFragment>("Login", GetString(Resource.String.signin_text), args, ViewModel.SignInViewModel);
}
}
From there, I have a Fragment
public class SignInFragment : MvxFragment
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
return this.BindingInflate(Resource.Layout.SignInFragment, null);
}
}
and two ViewModels
public class AuthViewModel : MvxViewModel
{
public AuthViewModel()
{
SignInViewModel = Mvx.IocConstruct<SignInViewModel>();
RegisterViewModel = Mvx.IocConstruct<RegisterViewModel>();
}
public MvxViewModel SignInViewModel { get; set; }
public MvxViewModel RegisterViewModel { get; set; }
}
public class SignInViewModel : MvxViewModel
{
public SignInViewModel(ISignInCommand signInCommand)
{
_signInCommand = signInCommand;
}
private string _email;
public string Email
{
get { return _email; }
set { _email = value; RaisePropertyChanged(() => Email); }
}
private string _password;
public string Password
{
get { return _password; }
set { _password = value; RaisePropertyChanged(() => Password); }
}
private ISignInCommand _signInCommand;
public ISignInCommand SignInCommand
{
get { return _signInCommand; }
set { _signInCommand = value; RaisePropertyChanged(() => SignInCommand); }
}
public void ShowViewModel<T>() where T : IMvxViewModel
{
base.ShowViewModel<T>();
}
}
Where might I be going wrong here?
I don't think this has anything to do with Fragments
Standard Buttons in Android don't have Command properties - they have Click events.
They also don't have CommandParameter properties - but MvvmCross provides a CommandParameter converter to allow you to do bindings like:
local:MvxBind="Click CommandParameter(VMCommandName, VMCommandParameterName)"
If you want to add Command and CommandParameter to a MyButton this can be done quite easily:
public class MyButton : Button {
public MyButton(Context c, IAttributeSet a) : base (c, a) {
Click += (s,e) => {
if (Command == null) return;
if (!Command.CanExecute(CommandParameter)) return;
Command.Execute(CommandParameter);
}
}
public ICommand Command {get;set;}
public object CommandParameter {get;set;}
}
Used in axml as:
<MyButton local:MvxBind="Command VMCommandName; CommandParameter VMCommandParameterName" />
Related
I am writing an Android app with a tab. I was following the old method in the sample "FragmentSample". It was working fine but I am evaluating to switch to viewpager.
In FragmentSample:
TabViewModel creates an instance of viewmodel for each individual tab
(Vm1, Vm2...).
In TabView, each tab fragment (Tab1Fragment,
Tab2Fragment...) are explicitly associated to the viewmodel (Vm1,
Vm2...) created in TabViewModel.
It is perfect as I could do some navigation initialization to Vm1,
Vm2 in TabViewModel.
public class TabViewModel : BaseViewModel
{
public TabViewModel()
{
Vm1 = Mvx.IocConstruct<FirstTabViewModel>();
Vm2 = Mvx.IocConstruct<SecondTabViewModel>();
Vm3 = Mvx.IocConstruct<ThirdTabViewModel>();
}
public BaseViewModel Vm1 { get; set; }
public BaseViewModel Vm2 { get; set; }
public BaseViewModel Vm3 { get; set; }
}
public class TabView : MvxTabsFragmentActivity
{
public TabViewModel TabViewModel
{
get { return (TabViewModel)base.ViewModel; }
}
public TabView()
: base(Resource.Layout.Page_TabView, Resource.Id.actualtabcontent)
{
}
protected override void AddTabs(Bundle args)
{
AddTab<Tab1Fragment>("Tab1", "Tab 1", args, TabViewModel.Vm1);
AddTab<Tab2Fragment>("Tab2", "Tab 2", args, TabViewModel.Vm2);
// note that
AddTab<Tab3Fragment>("Tab3.1", "Tab 3.1", args, TabViewModel.Vm3);
AddTab<Tab3Fragment>("Tab3.2", "Tab 3.2", args, TabViewModel.Vm3);
AddTab<Tab3BigFragment>("Tab3.3", "Tab 3.3", args, TabViewModel.Vm3);
}
}
In the latest sample project "Example" in MvvmCross-All:
ExampleViewPagerStateViewModel create an instance of RecyclerViewModel
ExampleViewPagerStateFragment defines the tabs (RecyclerView
1...5) with MvxCachingFragmentStatePagerAdapter.
When MvxCachingFragmentStatePagerAdapter is executed, another
instance of RecyclerViewModel will be created
RecyclerViewModel created in ExampleViewPagerStateViewModel seems to
be completely irrelevant to the tab built. I commented out the
creation in ExampleViewPagerStateViewModel and there was no change to
the app behavior.
RecyclerViewModel was created twice. It is the same in
ExampleViewPagerFragment in the same project, and in the old version
of this sample XPlatformMenus.
public class ExampleViewPagerStateViewModel
: MvxViewModel
{
public RecyclerViewModel Recycler { get; private set; }
public ExampleViewPagerStateViewModel()
{
Recycler = new RecyclerViewModel();
}
}
public class ExampleViewPagerStateFragment : BaseStateFragment<ExampleViewPagerStateViewModel>
{
protected override int FragmentId => Resource.Layout.fragment_example_viewpager_state;
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);
var viewPager = view.FindViewById<ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxCachingFragmentStatePagerAdapter.FragmentInfo>
{
//new MvxCachingFragmentStatePagerAdapter.FragmentInfo("RecyclerView 1", typeof (RecyclerViewFragment),
// typeof (RecyclerViewModel)),
//new MvxCachingFragmentStatePagerAdapter.FragmentInfo("RecyclerView 2", typeof (RecyclerViewFragment),
// typeof (RecyclerViewModel)),
//new MvxCachingFragmentStatePagerAdapter.FragmentInfo("RecyclerView 3", typeof (RecyclerViewFragment),
// typeof (RecyclerViewModel)),
//new MvxCachingFragmentStatePagerAdapter.FragmentInfo("RecyclerView 4", typeof (RecyclerViewFragment),
// typeof (RecyclerViewModel)),
new MvxCachingFragmentStatePagerAdapter.FragmentInfo("RecyclerView 5", typeof (RecyclerViewFragment),
typeof (RecyclerViewModel))
};
viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(Activity, ChildFragmentManager, fragments);
}
var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);
return view;
}
}
My questions are:
What is the usage of creating RecyclerViewModel in
ExampleViewPagerStateViewModel in "Example"?
In FragmentSample, Tab3.1 Tab3.2 Tab3.3 are sharing the same Vm3. Can
I do the same thing with ViewPager? Is there any way I can specify
the tab view (RecyclerView 1...5) to associate to the
RecyclerViewModel created in ExampleViewPagerStateViewModel but not a
new instance?
Thanks.
Just found that it could be done by changing the third parameter of FragmentInfo to Recycler created in RecyclerViewModel. The sample should make the change.
How to force WCF Rest client to use Json deserializer regardless of content-type?
I am invoking a REST based web service through WCF.
The service returns JSON body, but has content-type "Application/xml". The WCF framework is now giving me the XmlException.
public class MessageFormatter : IClientMessageFormatter
{
private readonly IClientMessageFormatter _formatter;
public MessageFormatter(IClientMessageFormatter formatter)
{
_formatter = formatter;
}
public object DeserializeReply(System.ServiceModel.Channels.Message message, object[] parameters)
{
return _formatter.DeserializeReply(message, parameters);
}
}
that _formatter.DeserializeReply is throwing XmlException. I can't find any example anywhere to force json deserialization on reply.
Edit - The "message" object when moused over is throwing "{... Error reading body: System.Xml.XmlException: The data at the root level is invalid. Line 1, position 1. ...}"
That same object in another one of my project that communicate with a different REST service (Picasa web services) has a what seems like a xml serialised version of JSON object?? So the problem seems further up the stream. I need to find where this object is originating from. I'll go play around with MessageEncoder class.
Edit - (Adding more info)
public class MyBinding : WebHttpBinding
{
public MyBinding(WebHttpSecurityMode mode)
: base(mode)
{
}
public override BindingElementCollection CreateBindingElements()
{
var result = base.CreateBindingElements();
var replacements = result.OfType<MessageEncodingBindingElement>().ToList();
foreach (var messageEncodingBindingElement in replacements)
{
var index = result.IndexOf(messageEncodingBindingElement);
result.Remove(messageEncodingBindingElement);
result.Insert(index, new MyMessageEncodingBindingElement(messageEncodingBindingElement));
}
return result;
}
}
public class MyMessageEncodingBindingElement : MessageEncodingBindingElement
{
private readonly MessageEncodingBindingElement _element;
public MyMessageEncodingBindingElement(MessageEncodingBindingElement element)
{
_element = element;
}
public override BindingElement Clone()
{
var result = _element.Clone();
if (result is MessageEncodingBindingElement)
return new MyMessageEncodingBindingElement(result as MessageEncodingBindingElement);
return result;
}
public override MessageEncoderFactory CreateMessageEncoderFactory()
{
return new MyMessageEncoderFactory(_element.CreateMessageEncoderFactory());
}
}
The method CreateMessageEncoderFactory() is never called even when the constructor and Clone method are hit when breakpoints are set. Any help? I'm trying to set a custom MessageEncoder and MessageEncoderFactory class to modify the instantiation process of the Message object.
You can use a WebContentTypeMapper for that. That's a property of the WebHttpBinding, and you can customize how the deserialization will be done by the encoder from that binding, including forcing it to always use the JSON deserializer, regardless of the incoming message's Content-Type. The code below shows how this can be done.
public class StackOverflow_13225272
{
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
public override string ToString()
{
return string.Format("Person[Name={0},Age={1}]", Name, Age);
}
}
[ServiceContract]
public interface ITest
{
[WebGet(ResponseFormat = WebMessageFormat.Json)]
Person GetPerson(string responseContentType);
}
public class Service : ITest
{
public Person GetPerson(string responseContentType)
{
WebOperationContext.Current.OutgoingResponse.ContentType = responseContentType;
return new Person { Name = "John Doe", Age = 29 };
}
}
class AllJsonContentTypeMapper : WebContentTypeMapper
{
public override WebContentFormat GetMessageFormatForContentType(string contentType)
{
return WebContentFormat.Json;
}
}
public static void Test()
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress));
host.Open();
Console.WriteLine("Host opened");
#if USE_NETFX4
// This works on .NET 4.0 and beyond
WebHttpBinding binding = new WebHttpBinding();
binding.ContentTypeMapper = new AllJsonContentTypeMapper();
#else
// This works on .NET 3.5
CustomBinding binding = new CustomBinding(new WebHttpBinding());
binding.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new AllJsonContentTypeMapper();
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
#endif
ChannelFactory<ITest> factory = new ChannelFactory<ITest>(binding, new EndpointAddress(baseAddress));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
ITest proxy = factory.CreateChannel();
Console.WriteLine("With JSON: {0}", proxy.GetPerson("application/json"));
Console.WriteLine("With XML: {0}", proxy.GetPerson("application/xml"));
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
This might work.
public class ForceJsonClientMessageFormatter : IClientMessageFormatter
{
private readonly DataContractJsonSerializer _jsonSerializer;
public ForceJsonClientMessageFormatter(Type responseType)
{
_jsonSerializer = new DataContractJsonSerializer(responseType);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
throw new NotImplementedException("This client message formatter is for replies only!");
}
public object DeserializeReply(Message message, object[] parameters)
{
string messageBody = message.GetBody<string>();
using (MemoryStream messageStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
{
messageStream.Seek(0, SeekOrigin.Begin);
object deserializedObject = _jsonSerializer.ReadObject(messageStream);
return deserializedObject;
}
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
return new ForceJsonClientMessageFormatter(operationDescription.Messages[1].Body.ReturnValue.Type);
}
}
I haven't tried it, but I think this will work. You can create a custom IClientMessageFormatter which overwrites the message format to Json, wrap that in a behavior, and then apply that behavior to your client endpoint configuration.
public class ForceJsonClientMessageFormatterDecorator : IClientMessageFormatter
{
private readonly IClientMessageFormatter _decoratedFormatter;
public ForceJsonClientMessageFormatterDecorator(IClientMessageFormatter decoratedFormatter)
{
_decoratedFormatter = decoratedFormatter;
}
public object DeserializeReply(Message message, object[] parameters)
{
message.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
return _decoratedFormatter.DeserializeReply(message, parameters);
}
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
{
return _decoratedFormatter.SerializeRequest(messageVersion, parameters);
}
}
public class ForceJsonWebHttpBehavior : WebHttpBehavior
{
protected override IClientMessageFormatter GetReplyClientFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
IClientMessageFormatter decoratedFormatter = base.GetReplyClientFormatter(operationDescription, endpoint);
return new ForceJsonClientMessageFormatterDecorator(decoratedFormatter);
}
}
Maybe abstract typed factories are not an easy point to start with Windsor (2.5.3 if it matters) but I've got to do it anyway.
I'm trying to build a factory giving back processors depending on message type. So far i've scavenged from different places following code:
public class Complicato
{
public static void Do(string[] args)
{
IKernel kernel = new DefaultKernel();
IWindsorContainer container = new WindsorContainer();
kernel.AddFacility<TypedFactoryFacility>();
container.Install();
container.Register(
Component.For<HandlerSelector, ITypedFactoryComponentSelector>(),
AllTypes.FromThisAssembly().BasedOn(typeof(ITrier<>))
.WithService.Base().Configure(conf => conf.LifeStyle.Is(LifestyleType.Transient)),
Component.For<Factor>(),
Component.For<ITryFactory>().AsFactory(c => c.SelectedWith<HandlerSelector>()).LifeStyle.Singleton);
var factor = container.Resolve<Factor>();
var factory = container.Resolve<ITryFactory>();
}
}
public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
return typeof(ITrier<>).MakeGenericType(arguments[0].GetType());
}
}
public class Factor
{
private ITryFactory factory;
public void Try(IWhat onto)
{
factory.GetTrier(onto).Try(onto);
}
}
public interface ITryFactory
{
ITrier<IWhat> GetTrier(IWhat onto);
void Release(object elem);
}
public interface IWhat { }
public interface ITrier<in TWhat> where TWhat : IWhat
{
void Try(TWhat input);
}
public class TrierYes : ITrier<WhatYes>
{
public void Try(WhatYes input) { Console.WriteLine("Yes? " + input.Aye()); }
}
public class TrierNo : ITrier<WhatNot>
{
public void Try(WhatNot input) { Console.WriteLine("No? " + input.Naa()); }
}
public class WhatYes : IWhat
{
public bool Aye() { return true; }
}
public class WhatNot : IWhat
{
public bool Naa() { return false; }
}
Main problem here is that id doesn't work. First I get Factor with factory of null and then as a consequence trying to resolve factory explicitely gives me ComponentActivator: could not proxy Factories.Complex.ITryFactory with inner message of The interceptor Castle.TypedFactory.Interceptor could not be resolved and "Keys (components with specific keys) - Castle.TypedFactory.Interceptor which was not registered" in container. I don't even know if the Handler selector works, it's not in question so far.
If I make ITrier not generic - it suddenly starts working but it's definitely not what I'm trying to achieve.
So do I make some silly beginners mistake in Windsor configuration or misunderstand the idea of typed factory?
For completeness sake, here's the exception message:
Castle.MicroKernel.ComponentActivator.ComponentActivatorException was unhandled
Message=ComponentActivator: could not proxy Factories.Complex.ITryFactory
Source=Castle.Windsor
StackTrace:
at Castle.MicroKernel.ComponentActivator.DefaultComponentActivator.CreateInstance(CreationContext context, Object[] arguments, Type[] signature) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\ComponentActivator\DefaultComponentActivator.cs:line 166
InnerException: Castle.MicroKernel.Resolvers.DependencyResolverException
Message=The interceptor Castle.TypedFactory.Interceptor could not be resolved
Source=Castle.Windsor
StackTrace:
at Castle.Core.InterceptorReference.Castle.MicroKernel.IReference<Castle.DynamicProxy.IInterceptor>.Resolve(IKernel kernel, CreationContext context) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Core\InterceptorReference.cs:line 142
And the winner is
container.AddFacility<TypedFactoryFacility>(); // good code
instead of
kernel.AddFacility<TypedFactoryFacility>(); // bad code
Now I only have the issues of not injected factory and improper HandlerSelector.
NullReference was solved by introducing explicit initializing constructor to the Factor. I don't know why I thought it works without.
Final version of the handler interface is following:
public interface ITrier<out TWhat> where TWhat: IWhat
{
void Try(IWhat input);
}
To permit covariance. Not über-elegant as requires unnecessary cast and handlers loosen their typedness. But this is cruel reality. You're either co or contra-variant.
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;
}
if i say have code that works like this:
private static void LoadFromAssemblies(IKernel kernel)
{
string appPath = HttpContext.Current.Request.MapPath(HttpContext.Current.Request.ApplicationPath);
kernel.Scan(a =>
{
a.FromAssembliesInPath(string.Format(#"{0}\Extensions", appPath));
a.AutoLoadModules();
a.BindWithDefaultConventions();
a.InRequestScope();
});
}
and just assume that each class defined in the target assembly has a string argument in the constructor, how would i go about passing in the string argument from the code above?
Do i instead use an Interceptor?
Thanks in advance, John
In my project into some repositories I pass ISession (nHibernate) and to others connectionString for DataContext(Linq2SQL)
To pass the connection string I have created LinqConfiguration class
public class LinqConfiguration : ILinqConfiguration
{
private readonly string _connectionString;
public LinqConfiguration(string connectionString)
{
_connectionString = connectionString;
}
public string GetConnectionString()
{
return _connectionString;
}
}
My repository looks like this:
public class WebClientRepository : IWebClientRepository
{
private readonly WebClientDataClassesDataContext datacontext;
private ILinqConfiguration _linqconfig;
public WebClientRepository(ILinqConfiguration linqconfig)
{
_linqconfig = linqconfig;
datacontext = new WebClientDataClassesDataContext(_linqconfig.GetConnectionString());
}
//....
}
and binding using Conventions:
public class LinqRepositoryModule: NinjectModule
{
public override void Load()
{
Bind<ILinqConfiguration>()
.To<LinqConfiguration>()
.WithConstructorArgument("connectionString",
ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString
);
IKernel ninjectKernel = this.Kernel;
ninjectKernel.Scan(kernel =>
{
kernel.FromAssemblyContaining<IWebClientRepository>();
kernel.FromAssemblyContaining<WebClientRepository>();
kernel.Where(t => t != typeof(LinqConfiguration)); // interface is in the same assembly and it is already binded
kernel.BindWithDefaultConventions();
kernel.AutoLoadModules();
kernel.InRequestScope();
});
}
}