Castle.Windsor - How to implement TypedFactoryFacility - dependency-injection

Recently, I developed a component , using factory pattern. However, I did a research. on how to improve it using TypedFactoryFacility, since we are using Castle.WIndsor.
Can you please provide a simple complete example? I have read few of them but still can't really fully understand . SO far, my code looks like that :
public class DynamoStoreService : IDynamoStoreService
{
private IDynamoStoreFactory _dynamoStoreFactory;
public DynamoStoreService(IDynamoStoreFactory dynamoStoreFactory)
{
_dynamoStoreFactory=dynamoStoreFactory;
}
public IDynamoStore GetProductDataDynamoStore(string storageAccount)
{
return _dynamoStoreFactory.Create(storageAccount);
}
}
public class DynamoStoreFactory : IDynamoStoreFactory
{
private IStorageAccountSelector _storageAccountSelector;
public DynamoStoreFactory(IStorageAccountSelector storageAccountSelector)
{
_storageAccountSelector = storageAccountSelector;
}
public IDynamoStore Create(string storageAccount)
{
return new AzureKeyValueStore(_storageAccountSelector.GetCredentials(storageAccount).StorageAccount, "pointerfiles");
}
}
public class StorageAccountSelector : IStorageAccountSelector
{
private readonly IConfigurationSettings _settings;
public StorageAccountSelector(IConfigurationSettings settings)
{
_settings = settings;
}
BlobCredentials IStorageAccountSelector.GetCredentials(string storageAccount)
{
return new BlobCredentials()
{
Container = string.Empty,
StorageAccount = GetStorageAccount(storageAccount)
};
}
private string GetStorageAccount(string storageAccount)
{
switch (storageAccount)
{
case "CustomerPolarisingCategoryBlobStorageAccountKey":
return _settings.CustomerPolarisingCategoryBlobStorageAccount;
case "CustomerPolarisingSegmentBlobStorageAccountKey":
return _settings.CustomerPolarisingSegmentBlobStorageAccount;
case "P2ProductSimilarityBlobStorageAccountKey":
return _settings.P2ProductSimilarityBlobStorageAccount;
case "ProductPolarisingCategoryBlobStorageAccountKey":
return _settings.ProductPolarisingCategoryBlobStorageAccount;
case "ProductPolarisingSegmentBlobStorageAccountKey":
return _settings.ProductPolarisingSegmentBlobStorageAccount;
case "SignalBlobStorageAccountKey":
return _settings.SignalBlobStorageAccount;
}
return string.Empty;
}
}
}
So basically, the IDynamostore , whenvever called, we need to be able to pass a different connection string. I have figured out the above design.. could this be improved using TypedFactoryFacility?
Thanks

Maybe the code below can give you an idea about how to use the TypedFactoryFacility. If you have studied it and have questions about it, please let me know.
Kind regards,
Marwijn.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace ConsoleApplication3
{
public class TypedFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
private readonly StorageAccountSelector _storageAccountSelector;
public TypedFactoryComponentSelector(StorageAccountSelector storageAccountSelector)
{
_storageAccountSelector = storageAccountSelector;
}
protected override System.Collections.IDictionary GetArguments(MethodInfo method, object[] arguments)
{
var dictionary = new Dictionary<string, object>();
dictionary.Add("mappedStorageAccount", _storageAccountSelector.GetCredentials((string)arguments[0]).StorageAccount);
dictionary.Add("files", "pointerfiles");
return dictionary;
}
}
public interface IDynamoStore
{
}
public class AzureKeyValueStore : IDynamoStore
{
public AzureKeyValueStore(string mappedStorageAccount, string files)
{
Console.WriteLine(mappedStorageAccount);
Console.WriteLine(files);
}
}
public class BlobCredentials
{
public string Container { get; set; }
public string StorageAccount { get; set; }
}
public interface IDynamoStoreFactory
{
IDynamoStore Create(string storageAccount);
}
public class StorageAccountSelector
{
public BlobCredentials GetCredentials(string storageAccount)
{
return new BlobCredentials()
{
Container = string.Empty,
StorageAccount = GetStorageAccount(storageAccount)
};
}
public string GetStorageAccount(string storageAccount)
{
return storageAccount + "Mapped";
return string.Empty;
}
}
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<IDynamoStoreFactory>().AsFactory(new TypedFactoryComponentSelector(new StorageAccountSelector())),
Component.For<IDynamoStore>().ImplementedBy<AzureKeyValueStore>()
);
var factory = container.Resolve<IDynamoStoreFactory>();
factory.Create("storageAccount");
}
}
}

Related

No parameterless constructor defined for this object with Dependency Resolver

I'm currently following "Dependancy Injection on asp net mvc 5 tutorial" in youtube. https://www.youtube.com/watch?v=27DQn6kZDFM
I follow as he said but I'm having this error.
No parameterless constructor defined for this object.
My Controller is UnityDemoController
public class UnityDemoController : Controller
{
private readonly ILocalWeaherServiceProvider _localWeaherServiceProvider;
public UnityDemoController(ILocalWeaherServiceProvider localWeaherServiceProvider)
{
_localWeaherServiceProvider = localWeaherServiceProvider;
}
//
// GET: /UnityDemo/
public ActionResult Index()
{
string currentWeatherInMyArea = _localWeaherServiceProvider.GetLocalWeatherByZipCode("0006");
return View();
}
}
IocConfiguration.cs This Configuration is under App_Start folder
public static class IocConfiguration
{
public static void ConfigureIocUnityContaioner()
{
IUnityContainer container = new UnityContainer();
RegisterServices(container);
DependencyResolver.SetResolver(new MyUnityDependancyResolver(container));
}
private static void RegisterServices(IUnityContainer container)
{
container.RegisterType<ILocalWeaherServiceProvider, LocalWeatherServiceProvider>(); // This means when somebody call/need ILocalWeaherServiceProvider then provide new Instance of the LocalWeatherServiceProvider
}
}
MyUnityDependancyResolver.cs
public class MyUnityDependancyResolver : IDependencyResolver
{
private IUnityContainer _unityContainer;
public MyUnityDependancyResolver(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public object GetService(Type serviceType)
{
try
{
return _unityContainer.Resolve(serviceType);
}
catch (Exception)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _unityContainer.ResolveAll(serviceType);
}
catch (Exception)
{
return new List<object>();
}
}
}
Interface ILocalWeaherServiceProvider
public interface ILocalWeaherServiceProvider
{
string GetLocalWeatherByZipCode(string zipcode);
}
Service Class LocalWeatherServiceProvider
public class LocalWeatherServiceProvider : ILocalWeaherServiceProvider
{
public string GetLocalWeatherByZipCode(string zipcode)
{
return "Its is snowing right now in your Area : " + zipcode;
}
}
I have added Unity.
Can anyone tell me what went wrong here?
And avoid these kinds of error what are the things that I should look into these coding level?
I found out the solution by referring to below link.
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=97
Change the UnityDemoController class as below.
public class UnityDemoController : Controller
{
private readonly ILocalWeaherServiceProvider _localWeaherServiceProvider;
public UnityDemoController() : this(new LocalWeatherServiceProvider())
{
}
public UnityDemoController(ILocalWeaherServiceProvider localWeaherServiceProvider)
{
_localWeaherServiceProvider = localWeaherServiceProvider;
}
//
// GET: /UnityDemo/
public ActionResult Index()
{
string currentWeatherInMyArea = _localWeaherServiceProvider.GetLocalWeatherByZipCode("0006");
return View();
}
}

How can I incorporate this Castle Windsor DI code into my Controller and Repository code?

Note: I can't bountify this question yet (it's too new), but I will reward a good answer with 50 points, and a great answer with 100 (when possible).
I need to incorporate DI into my Web API project. I currently have the expected Model and Controller folders/classes, along with corresponding Repository classes.
That seemed to work well for awhile, but now I need to use DI with the Controllers so that I can pass an Interface type to the Controllers' constructor.
I'm struggling with just how to implement this; that is, how to incorporate the DI "extravaganza" into my existing Model/Controller/Repository structure. I have example DI code, but I don't know just how it should be applied to my project.
Perhaps some code is in order to try to make this clear. I will show a simple sample of what I've got, followed by the DI code I'd like to somehow incorporate into it / with it.
Here is the existing Model/Controller/Repository code:
MODEL
public class Department
{
public int Id { get; set; }
public int AccountId { get; set; }
public string Name { get; set; }
}
CONTROLLER
public class DepartmentsController : ApiController
{
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
public int GetCountOfDepartmentRecords()
{
return _deptsRepository.Get();
}
public IEnumerable<Department> GetBatchOfDepartmentsByStartingID(int ID, int CountToFetch)
{
return _deptsRepository.Get(ID, CountToFetch);
}
public void PostDepartment(int accountid, string name)
{
_deptsRepository.PostDepartment(accountid, name);
}
public HttpResponseMessage Post(Department department)
{
// Based on code 2/3 down http://www.codeproject.com/Articles/344078/ASP-NET-WebAPI-Getting-Started-with-MVC4-and-WebAP?msg=4727042#xx4727042xx
department = _deptsRepository.Add(department);
var response = Request.CreateResponse<Department>(HttpStatusCode.Created, department);
string uri = Url.Route(null, new { id = department.Id });
response.Headers.Location = new Uri(Request.RequestUri, uri);
return response;
}
REPOSITORY
public class DepartmentRepository : IDepartmentRepository
{
private readonly List<Department> departments = new List<Department>();
public DepartmentRepository()
{
using (var conn = new OleDbConnection(
#"Provider=Microsoft.ACE.OLEDB.12.0;User ID=BlaBlaBla...
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT td_department_accounts.dept_no,
IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name
FROM t_accounts INNER JOIN td_department_accounts ON
t_accounts.account_no = td_department_accounts.account_no ORDER BY
td_department_accounts.dept_no";
cmd.CommandType = CommandType.Text;
conn.Open();
int i = 1;
using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader())
{
while (oleDbD8aReader != null && oleDbD8aReader.Read())
{
int deptNum = oleDbD8aReader.GetInt16(0);
string deptName = oleDbD8aReader.GetString(1);
Add(new Department { Id = i, AccountId = deptNum, Name,
deptName });
i++;
}
}
}
}
}
public int Get()
{
return departments.Count;
}
private Department Get(int ID) // called by Delete()
{
return departments.First(d => d.Id == ID);
}
public IEnumerable<Department> Get(int ID, int CountToFetch)
{
return departments.Where(i => i.Id > ID).Take(CountToFetch);
}
public Department Add(Department dept)
{
if (dept == null)
{
throw new ArgumentNullException("Department arg was null");
}
// This is called internally, so need to disregard Id vals that already exist
if (dept.Id <= 0)
{
int maxId = departments.Max(d => d.Id);
dept.Id = maxId + 1;
}
if (departments != null) departments.Add(dept);
return dept;
}
public void PostDepartment(int accountid, string name)
{
int maxId = departments.Max(d => d.Id);
Department dept = new Department();
dept.Id = maxId + 1;
dept.AccountId = accountid;
dept.Name = name;
departments.Add(dept);
}
public void Post(Department department)
{
int maxId = departments.Max(d => d.Id);
department.Id = maxId + 1;
departments.Add(department);
}
public void Put(Department department)
{
int index = departments.ToList().FindIndex(p => p.Id == department.Id);
departments[index] = department;
}
public void Put(int id, Department department)
{
int index = departments.ToList().FindIndex(p => p.Id == id);
departments[index] = department;
}
public void Delete(int id)
{
Department dept = Get(id);
departments.Remove(dept);
}
And now here is the DI code that I want to incorporate
Classes in the DIInstallers folder:
IDepartmentProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace HandheldServer.DIInstallers
{
public interface IDepartmentProvider
{
// These are the methods that are in the sample example IAuthProvider interface; I don't know what I need yet, though...
//bool Authenticate(string username, string password, bool createPersistentCookie);
//void SignOut();
}
}
DepartmentProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace HandheldServer.DIInstallers
{
public class DepartmentProvider : IDepartmentProvider
{
// TODO: Implement methods in IDepartmentProvider, once they have been added
}
}
DepartmentProviderInstaller.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
namespace HandheldServer.DIInstallers
{
public class DepartmentProviderInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(IDepartmentProvider))
.WithServiceAllInterfaces());
// If I declare/implement more interface types (other than IDepartmentProvider), I assume there would be another container.Register() call for each of them?
}
}
}
Classes in the DIPlumbing folder:
WindsorCompositionRoot.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Castle.Windsor;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
namespace HandheldServer.DIPlumbing
{
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)this.container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => this.container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
}
WindsorControllerFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Castle.MicroKernel;
namespace HandheldServer.DIPlumbing
{
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
public override void ReleaseController(IController controller)
{
kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)kernel.Resolve(controllerType);
}
}
}
The Global.asax.cs file
using System;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Castle.Windsor;
using Castle.Windsor.Installer;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.Http.Dispatcher;
using HandheldServer.DIPlumbing;
namespace HandheldServer
{
public class WebApiApplication : System.Web.HttpApplication
{
private static IWindsorContainer container;
protected void Application_Start()
{
BootstrapContainer();
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
// Code that runs when an unhandled error occurs
void Application_Error(object sender, EventArgs e)
{
// Get the exception object.
Exception exc = Server.GetLastError();
log.Error(exc.Message);
// Clear the error from the server
Server.ClearError();
}
private static void BootstrapContainer()
{
container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator), new WindsorCompositionRoot(container));
}
protected void Application_End()
{
container.Dispose();
}
}
}
So, I think I've basically got the code I need, but how to fold the DI code into my previous (Model/Controller/Repository) code is the part that has me stumped.
You can simply use WebApiContrib.IoC.CastleWindsor (Nuget).
This test should give you an idea of how to use it.

Mvvmcross MvxSimpleTableViewSource Binding

I'm trying to create custom cells for my MvxTableViewController as showed in Stuart Lodge videos N=3 & N=6.5 but it fails to bind data.
Here the working version (the one with basic cells)
using Cirrious.MvvmCross.Binding.BindingContext;
using Cirrious.MvvmCross.Binding.Touch.Views;
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.MvvmCross.ViewModels;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Next.Client.Application.Core.Entities.Observations;
using Next.Client.Application.Core.ViewModels;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Next.Client.Application.iOS.Views
{
[Register("ObsSearchView")]
public partial class ObsSearchView : MvxTableViewController
{
public static readonly NSString CellIdentifier = new NSString("ObservationCell");
public ObsSearchView()
{
}
public ObsSearchView(IntPtr handle)
: base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Request = new MvxViewModelRequest<ObsSearchViewModel>(null, null, new MvxRequestedBy());
LoadData();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
Title = NSBundle.MainBundle.LocalizedString("Liste Observations", "Liste Observations");
}
public override void ViewWillDisappear(bool animated)
{
Title = NSBundle.MainBundle.LocalizedString("Back", "Liste Observations");
base.ViewDidDisappear(animated);
}
public void LoadData()
{
var source = new MvxStandardTableViewSource(
TableView,
UITableViewCellStyle.Subtitle,
CellIdentifier,
"TitleText BrutText; DetailText DateTimeHuman",
UITableViewCellAccessory.DisclosureIndicator
);
TableView.Source = source;
var set = this.CreateBindingSet<ObsSearchView, Core.ViewModels.ObsSearchViewModel>();
set.Bind(source).To(vm => vm.Observations);
set.Bind(source).For(s => s.SelectionChangedCommand).To(vm => vm.SelectedObsCommand);
set.Apply();
TableView.ReloadData();
}
}
}
and here the modified version to add custom cells:
using Cirrious.MvvmCross.Binding.BindingContext;
using Cirrious.MvvmCross.Binding.Touch.Views;
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.MvvmCross.ViewModels;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Next.Client.Application.Core.Entities.Observations;
using Next.Client.Application.Core.ViewModels;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace Next.Client.Application.iOS.Views
{
[Register("ObsSearchView")]
public partial class ObsSearchView : MvxTableViewController
{
public static readonly NSString CellIdentifier = new NSString("ObservationCell");
public ObsSearchView()
{
}
public ObsSearchView(IntPtr handle)
: base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Request = new MvxViewModelRequest<ObsSearchViewModel>(null, null, new MvxRequestedBy());
LoadData();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
Title = NSBundle.MainBundle.LocalizedString("Liste Observations", "Liste Observations");
}
public override void ViewWillDisappear(bool animated)
{
Title = NSBundle.MainBundle.LocalizedString("Back", "Liste Observations");
base.ViewDidDisappear(animated);
}
public void LoadData()
{
var source = new MvxSimpleTableViewSource(
TableView,
ObservationCell.Key,
ObservationCell.Key
);
TableView.Source = source;
TableView.ReloadData();
}
}
}
with the custom cell class
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Cirrious.MvvmCross.Binding.Touch.Views;
using Cirrious.MvvmCross.Binding.BindingContext;
using Next.Client.Application.Core.ViewModels;
using Next.Client.Application.Core.Entities.Observations;
namespace Next.Client.Application.iOS
{
public partial class ObservationCell : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName ("ObservationCell", NSBundle.MainBundle);
public static readonly NSString Key = new NSString ("ObservationCell");
public ObservationCell (IntPtr handle) : base (handle)
{
this.DelayBind(() => {
var set = this.CreateBindingSet<ObservationCell, Observation>();
set.Bind(MainLbl).To(observation => observation.BrutText);
set.Bind(SubLeftLbl).To(observation => observation.DateTimeHuman);
set.Bind(SubRightLbl).To(observation => observation.Praticien.Personne.DisplayFullName);
set.Apply();
});
}
public static ObservationCell Create ()
{
return (ObservationCell)Nib.Instantiate (null, null) [0];
}
}
}
and finally the Observation entity
using Next.Client.Application.Core.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Next.Client.Application.Core.Entities;
using System.Globalization;
namespace Next.Client.Application.Core.Entities.Observations
{
public class Observation : Entity
{
#region Constructors
#endregion
#region Constantes
private readonly List<String> _month = new List<String>{
"",
"jan.",
"fev.",
"mars",
"avr.",
"mai",
"juin",
"jui.",
"aout",
"sep.",
"oct.",
"nov.",
"dec."
};
#endregion
#region Simple Properties
#region Foreign keys
private int _praticienId;
public int PraticienId
{
get { return _praticienId; }
set { _praticienId = value; OnPropertyChange(() => PraticienId); }
}
private int _sejourId;
public int SejourId
{
get { return _sejourId; }
set { _sejourId = value; OnPropertyChange(() => SejourId); }
}
private int _categoryId;
public int CategoryId
{
get { return _categoryId; }
set { _categoryId = value; OnPropertyChange(() => CategoryId); }
}
#endregion
private DateTime _dateTime;
public DateTime DateTime
{
get { return _dateTime; }
set { _dateTime = value; OnPropertyChange(() => DateTime); OnPropertyChange(() => DateTimeHuman); }
}
public String DateTimeHuman
{
get
{
CultureInfo culture = new CultureInfo("fr-FR");
return DateTime.ToString("f", culture);
}
}
public string DisplayDateTime
{
get { return string.Format("{0} {1} {2} {3}h{4:00}", _dateTime.Day, _month[_dateTime.Month], _dateTime.Year, _dateTime.Hour, _dateTime.Minute); }
}
private int _status;
public int Status
{
get { return _status; }
set { _status = value; OnPropertyChange(() => Status); }
}
private int _type;
public int Type
{
get { return _type; }
set { _type = value; OnPropertyChange(() => Type); }
}
private bool _private;
public bool Private
{
get { return _private; }
set { _private = value; OnPropertyChange(() => Private); OnPropertyChange(() => DisplayPrivacy); }
}
public string DisplayPrivacy
{
get { if (_private) return "OUI"; else return "NON"; }
}
private string _brutText;
public string BrutText
{
get { return _brutText; }
set { _brutText = value; OnPropertyChange(() => BrutText); }
}
#endregion
#region Navigation Properties
private Praticien _praticien;
public Praticien Praticien
{
get { return _praticien; }
set
{
Praticien old = _praticien;
_praticien = value;
CollectionHelper.ManyToOne(this, old, value, _GetManyToOneCollection);
OnPropertyChange(() => Praticien);
}
}
private Sejour _sejour;
public Sejour Sejour
{
get { return _sejour; }
set
{
Sejour old = _sejour;
_sejour = value;
CollectionHelper.ManyToOne(this, old, value, _GetManyToOneCollection);
OnPropertyChange(() => Sejour);
}
}
private Category _category;
public Category Category
{
get { return _category; }
set
{
Category old = _category;
_category = value;
CollectionHelper.ManyToOne(this, old, value, _GetManyToOneCollection);
OnPropertyChange(() => Category);
}
}
private ObservableCollection<BinaryObservation> _datas;
public ObservableCollection<BinaryObservation> Datas
{
get
{
if (_datas == null)
{
_datas = new ObservableCollection<BinaryObservation>();
CollectionHelper.OneToMany(this, _GetOneToMany, _SetOneToMany, _datas);
}
return _datas;
}
set { _datas = value; OnPropertyChange(() => Datas); }
}
#endregion
#region Association Fixup
private static ObservableCollection<Observation> _GetManyToOneCollection(Sejour sejour)
{
return sejour.Observations;
}
private static ObservableCollection<Observation> _GetManyToOneCollection(Category category)
{
return category.Observations;
}
private static ObservableCollection<Observation> _GetManyToOneCollection(Praticien praticien)
{
return praticien.Observations;
}
#region binary observation (datas)
private static Observation _GetOneToMany(BinaryObservation binaryObservation)
{
return binaryObservation.Observation;
}
private static void _SetOneToMany(BinaryObservation binaryObservation, Observation observation)
{
binaryObservation.Observation = observation;
}
#endregion
#endregion
}
}
when I build I get no error and I can run the debugger without errors either, but when using the custom cells nothing show up, so it seems the binding isn't done the right way.
Thanks for your time
In your modified ObsView you are never actually binding the ItemsSource for TableSource - so the table source doesn't know what collection to show
In the N+1 3 Kittens tutorial this is done using:
var set = this.CreateBindingSet<FirstView, FirstViewModel>();
set.Bind(source).To(vm => vm.Kittens);
set.Apply();
See https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-03-KittenView_Mac/KittenView.Touch/Views/FirstView.cs#L24
Similarly, in N=6:
var set = this.CreateBindingSet<FirstView, Core.ViewModels.FirstViewModel>();
// ...
set.Bind(source).To(vm => vm.Results);
// ...
set.Apply();
See https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-07-BooksPlus/Books.Touch/Views/FirstView.cs#L45

asp .net mvc custom model binding fails

I wrote a custom binder, but i can't seem to get it running.
Here's my code:
public abstract class SlideItem
{
public string PlaceHolderName { get; set; }
public uint PlaceHolderID { get; set; }
public uint ItemType { get; set; }
}
public class TitleSlideItem : SlideItem
{
...
public TitleSlideItem()
{
ItemType = 1;
}
}
public class ParagraphSlideItem : SlideItem
{
...
public ParagraphSlideItem()
{
ItemType = 2;
}
}
public class SlideItemBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
System.Diagnostics.Trace.WriteLine("BindModel is working");
var values = (ValueProviderCollection)bindingContext.ValueProvider;
var placeHolderName = (string)values.GetValue("PlaceHolderName").ConvertTo(typeof(string));
var placeHolderID = (uint)values.GetValue("PlaceHolderID").ConvertTo(typeof(uint));
var itemType = (uint)values.GetValue("ItemType").ConvertTo(typeof(uint));
switch (itemType)
{
case 1:
System.Diagnostics.Trace.WriteLine("TitleSlideItemBinder");
return (SlideItem)new TitleSlideItem { PlaceHolderName = placeHolderName };
case 2:
System.Diagnostics.Trace.WriteLine("ParagraphSlideItem");
return (SlideItem)new ParagraphSlideItem { PlaceHolderName = placeHolderName };
case 3:
System.Diagnostics.Trace.WriteLine("TextSlideItem");
return (SlideItem)new TextSlideItem { PlaceHolderName = placeHolderName };
case 4:
System.Diagnostics.Trace.WriteLine("PictureSlideItem");
return (SlideItem)new PictureSlideItem { PlaceHolderName = placeHolderName };
default:
System.Diagnostics.Trace.WriteLine("this should never-ever-ever-ever happen");
//this should never-ever-ever-ever happen
return (SlideItem)new TextSlideItem { PlaceHolderName = placeHolderName };
}
}
}
I added this to my global.asax.cs:
ModelBinders.Binders.Add(new KeyValuePair<Type, IModelBinder>(typeof(SlideItem), new SlideItemBinder()));
but when i try to run this:
[System.Web.Http.HttpPost]
public HttpResponseMessage Create(IList<SlideContent> l)
{
...
}
i still get a System.MissingMethodException saying: cannot create abstract class
Where am i going wrong?
Sincerely,
Zoli
Check this link.you might find the solution here: ASP.NET MVC 2 - Binding To Abstract Model
The answer has a custom model binder.

StructureMap Question

This is the equivalent of what I'm trying to create with StructureMap:
new ChangePasswordWithNotificationAndLoggingService(
new ChangePasswordService(
new ActiveDirectoryRepository(new ActiveDirectoryCredentials()),
new TokenRepository("")),
new EmailNotificationService(new PasswordChangedNotification(new UserAccount())),
new LoggingService());
This is what I have right now:
ForRequestedType<IChangePasswordService>()
.TheDefault.Is.ConstructedBy(() =>
new ChangePasswordService(DependencyRegistrar.Resolve<IActiveDirectoryRepository>(),
DependencyRegistrar.Resolve<ITokenRepository>()))
.EnrichWith<IChangePasswordService>(x =>
new ChangePasswordWithNotificationAndLoggingService(x,
DependencyRegistrar.Resolve<INotificationService>(),
DependencyRegistrar.Resolve<ILoggingService>()));
I need to pass the UserAccount to the INotificationService...can't figure it out.
I've tried this:
DependencyRegistrar.With(new UserAccount { Username = "test" });
No luck...UserAccount always turns out null. I don't have to do it all with StructureMap, I'm open to any suggestions.
This is what I currently have working:
public static IChangePasswordService ChangePasswordService(UserAccount userAccount)
{
return new ChangePasswordWithNotificationService(
new ChangePasswordService(ActiveDirectoryRepository(), TokenRepository()),
new EmailNotificationService(new PasswordChangedNotification(userAccount)));
}
Have you tried just using AutoWiring? These are all concrete classes with simple construction so StructureMap can figure out what you need.
For<IChangePasswordService>().Use<ChangePasswordService>();
Looking at your construction I think that this simple configuration might just work.
Edit
Regarding the comments.
You should use the With(T instance) method to have the container construct your IChangePasswordService using the given userAccount.
var userAccount = new UserAccount("derans");
var changePasswordService = container.With(userAccount).GetInstance<IChangePasswordService>();
Why not encapsulate the creation of the change password service into a factory - the factory is then an implemented as StructureMap factory that use a UserAccount passed in and the 'ObjectFactory' to create instances of the IIChangePasswordService as required?
I have demo'ed it below:
namespace SMTest
{
class Program
{
static void Main(string[] args)
{
// bootstrapper...
ObjectFactory.Configure(x => x.AddRegistry(new TestRegistry()));
// create factory for use later (IoC manages this)...
var changePasswordServiceFactory = ObjectFactory.GetInstance<IChangePasswordServiceFactory>();
var daveAccount = new UserAccount("Dave Cox");
var steveAccount = new UserAccount("Steve Jones");
var passwordService1 = changePasswordServiceFactory.CreateForUserAccount(daveAccount);
var passwordService2 = changePasswordServiceFactory.CreateForUserAccount(steveAccount);
}
}
public class TestRegistry : Registry
{
public TestRegistry()
{
Scan(x =>
{
x.TheCallingAssembly();
x.AssemblyContainingType(typeof(IChangePasswordService));
x.AssemblyContainingType(typeof(IActiveDirectoryRepository));
x.AssemblyContainingType(typeof(IActiveDirectoryCredentials));
x.AssemblyContainingType(typeof(ITokenRepository));
x.AssemblyContainingType(typeof(INotification));
x.AssemblyContainingType(typeof(INotificationService));
x.AssemblyContainingType(typeof(ILoggingService));
ForRequestedType<ILoggingService>().TheDefault.Is.OfConcreteType<MyLogger>();
ForRequestedType<IActiveDirectoryRepository>().TheDefault.Is.OfConcreteType<MyAdRepository>();
ForRequestedType<IActiveDirectoryCredentials>().TheDefault.Is.OfConcreteType<MyAdCredentials>();
ForRequestedType<ITokenRepository>().TheDefault.Is.OfConcreteType<MyTokenRepository>();
ForRequestedType<IChangePasswordService>().TheDefault.Is.OfConcreteType<ChangePasswordService>();
ForRequestedType<IChangePasswordServiceFactory>().CacheBy(InstanceScope.Singleton).TheDefault.Is.OfConcreteType<StructureMapChangePasswordServiceFactory>();
ForRequestedType<INotification>().TheDefault.Is.OfConcreteType<MyPasswordChangedNotification>();
ForRequestedType<INotificationService>().TheDefault.Is.OfConcreteType<MyEmailNotificationService>();
});
}
}
public interface ILoggingService
{
}
public class MyLogger : ILoggingService
{
}
public class UserAccount
{
public string Name { get; private set; }
public UserAccount(string name)
{
Name = name;
}
}
public interface INotification
{
}
public class MyPasswordChangedNotification : INotification
{
private readonly UserAccount _account;
private readonly ILoggingService _logger;
public MyPasswordChangedNotification(UserAccount account, ILoggingService logger)
{
_account = account;
_logger = logger;
}
}
public interface INotificationService
{
}
public class MyEmailNotificationService : INotificationService
{
private readonly INotification _notification;
private readonly ILoggingService _logger;
public MyEmailNotificationService(INotification notification, ILoggingService logger)
{
_notification = notification;
_logger = logger;
}
}
public interface ITokenRepository
{
}
public class MyTokenRepository : ITokenRepository
{
}
public interface IActiveDirectoryRepository
{
}
public interface IActiveDirectoryCredentials
{
}
public class MyAdCredentials : IActiveDirectoryCredentials
{
}
public class MyAdRepository : IActiveDirectoryRepository
{
private readonly IActiveDirectoryCredentials _credentials;
public MyAdRepository(IActiveDirectoryCredentials credentials)
{
_credentials = credentials;
}
}
public interface IChangePasswordService
{
}
public class ChangePasswordService : IChangePasswordService
{
private readonly IActiveDirectoryRepository _adRepository;
private readonly ITokenRepository _tokenRepository;
private readonly INotificationService _notificationService;
public ChangePasswordService(IActiveDirectoryRepository adRepository, ITokenRepository tokenRepository, INotificationService notificationService)
{
_adRepository = adRepository;
_tokenRepository = tokenRepository;
_notificationService = notificationService;
}
}
public interface IChangePasswordServiceFactory
{
IChangePasswordService CreateForUserAccount(UserAccount account);
}
public class StructureMapChangePasswordServiceFactory : IChangePasswordServiceFactory
{
public IChangePasswordService CreateForUserAccount(UserAccount account)
{
return ObjectFactory.With(account).GetInstance < IChangePasswordService>();
}
}
}

Resources