Rather than manually having to bind every class, what methods and patterns, if any, are recommended for automatically setting up bindings?
For example, the vast majority of bindings simply look like this:
Bind<ICustomerRepository>.To<CustomerRepository>();
Once modules get large, you can end up with 100s of bindings that all look exactly the same. Can this be automated?
check out the conventions extension:
https://github.com/ninject/ninject.extensions.conventions
using (IKernel kernel = new StandardKernel())
{
var scanner = new AssemblyScanner();
scanner.From(Assembly.GetExecutingAssembly());
scanner.BindWith<DefaultBindingGenerator>();
kernel.Scan(scanner);
var instance = kernel.Get<IDefaultConvention>();
instance.ShouldNotBeNull();
instance.ShouldBeInstanceOf<DefaultConvention>();
}
Related
The problem, essentially, is that I can't get my sitemap config to support multiple sitemaps. It's always looking for "default" even when I name my instances and request another. Now for the background.
I've been pouring over the docs for the new implementation of MVCSiteMapProvider. They are now using Dependency Injection to configure the SiteMapProvider. We have an existing StructureMap DI implementation, so I followed the instructions and added, in our case
ObjectFactory.Configure(x =>
{
...
x.AddRegistry<MvcSiteMapProviderRegistry>();
...
});
Then I started tweaking the MvcSiteMapProviderRegistry.cs file to implement my multiple sitemap scenario. I have multiple site map files, either will work as long as it's called "default". If I remove the "default" item then it breaks and complains that "default" is missing. Which I assume is because it can't find my instance. Here's how I have them defined. I suspect the problem is somewhere in here... the loader which it says I have to configure in the Global.asax is looking for ISiteMapLoader but I'm adding my multiple configuration to SiteMapBuilderSet... anyway here's the code.
// Register the sitemap builder
string absoluteFileName = HostingEnvironment.MapPath("~/Main.sitemap");
string absoluteFileName2 = HostingEnvironment.MapPath("~/Test.sitemap");
var xmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
.Ctor<string>("fileName").Is(absoluteFileName);
var reservedAttributeNameProvider = this.For<ISiteMapXmlReservedAttributeNameProvider>()
.Use<SiteMapXmlReservedAttributeNameProvider>()
.Ctor<IEnumerable<string>>("attributesToIgnore").Is(new string[0]);
var builder = this.For<ISiteMapBuilder>().Use<CompositeSiteMapBuilder>()
.EnumerableOf<ISiteMapBuilder>().Contains(y =>
{
y.Type<XmlSiteMapBuilder>()
.Ctor<ISiteMapXmlReservedAttributeNameProvider>().Is(reservedAttributeNameProvider)
.Ctor<IXmlSource>().Is(xmlSource);
y.Type<ReflectionSiteMapBuilder>()
.Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
.Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
y.Type<VisitingSiteMapBuilder>();
});
var xmlSource2 = this.For<IXmlSource>().Use<FileXmlSource>()
.Ctor<string>("fileName").Is(absoluteFileName2);
var builder2 = this.For<ISiteMapBuilder>().Use<CompositeSiteMapBuilder>()
.EnumerableOf<ISiteMapBuilder>().Contains(y =>
{
y.Type<XmlSiteMapBuilder>()
.Ctor<ISiteMapXmlReservedAttributeNameProvider>().Is(reservedAttributeNameProvider)
.Ctor<IXmlSource>().Is(xmlSource2);
y.Type<ReflectionSiteMapBuilder>()
.Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
.Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
y.Type<VisitingSiteMapBuilder>();
});
// Configure the builder sets
this.For<ISiteMapBuilderSetStrategy>().Use<SiteMapBuilderSetStrategy>()
.EnumerableOf<ISiteMapBuilderSet>().Contains(x =>
{
/* x.Type<SiteMapBuilderSet>()
.Ctor<string>("instanceName").Is("default")
.Ctor<bool>("securityTrimmingEnabled").Is(securityTrimmingEnabled)
.Ctor<bool>("enableLocalization").Is(enableLocalization)
.Ctor<ISiteMapBuilder>().Is(builder)
.Ctor<ICacheDetails>().Is(cacheDetails);*/
/*
x.Type<SiteMapBuilderSet>()
.Ctor<string>("instanceName").Is("MainSiteMapProvider")
.Ctor<bool>("securityTrimmingEnabled").Is(securityTrimmingEnabled)
.Ctor<bool>("enableLocalization").Is(enableLocalization)
.Ctor<ISiteMapBuilder>().Is(builder)
.Ctor<ICacheDetails>().Is(cacheDetails);*/
x.Type<SiteMapBuilderSet>()
.Ctor<string>("instanceName").Is("TestSiteMapProvider")
.Ctor<bool>("securityTrimmingEnabled").Is(securityTrimmingEnabled)
.Ctor<bool>("enableLocalization").Is(enableLocalization)
.Ctor<ISiteMapBuilder>().Is(builder2)
.Ctor<ICacheDetails>().Is(cacheDetails);
});
In my global.asax.cs I added
MvcSiteMapProvider.SiteMaps.Loader = Resolver.Get<ISiteMapLoader>();
and to reference in my view I have
#Html.MvcSiteMap("TestSiteMapProvider").Menu(false, true, true)
but it must not be able to find "TestSiteMapProvider" because it always displays "default" or complains if it doesn't exist.
I also thought it might have something to do with the Cache, as I see the filename referenced there, but I don't know how to add multiple instances to the cache, so I just disabled it. I'm really not doing anything fancy with my sitemaps anyway, and this whole thing is really feeling like massive overkill just to get some flippin automatic breadcrumbs!
Apparently there was another help doc that I wasn't aware of. I had completed all of the steps thus far properly, but I also needed to implement ISiteMapCacheKeyGenerator.
See this doc (which wasn't named this when I started.)
https://github.com/maartenba/MvcSiteMapProvider/wiki/Multiple-Sitemaps-in-One-Application
Is it possible to distribute a NHibernate-by-Code-Mapping over several classes?
E.g.
public class EntityMap1 : ClassMapping<Entity> {
Id(x => x.Id);
Property(x => x.PropertyOne);
}
public class EntityMap2 : ClassMapping<Entity> {
Property(x => x.PropertyTwo);
}
I tried it but the mapping of PropertyTwo was missing in the generated HBML. Is there some way to achieve this?
I don't believe NHibernate would be able to compile both together to create a singular mapping. If the goal is to use a different set of mappings in one app versus another, you need to simply create two different mappings. If the goal is to have subclasses, there is a SubclassMapping interface you can extend.
Edit:
In looking over my notes, an extension to my answer about creating a different set of mappings would be the case where you have some feature plugged into your app that needs a different (sometimes more, sometimes less involved) mapping. To do this you need to have NHibernate generate them separately and add them to the configuration separately. Using conventions, this creates two separate sets of mappings (which contain some overlapping, but differently mapped, entites) that are plugged into one configuration:
NHibernateConfiguration.BeforeBindMapping += (sender, args) => args.Mapping.autoimport = false;
var pluginMappings = new PluginMapper().Mappings;
foreach (var hbmMapping in pluginMappings)
NHibernateConfiguration.AddDeserializedMapping(hbmMapping, "PluginModel");
var mainAppMappings = new AppMapper().Mappings;
foreach (var hbmMapping in mainAppMappings)
NHibernateConfiguration.AddDeserializedMapping(hbmMapping, "AppModel");
As described in my comment to Fourth's answer the goal was that a plugin can modify the mapping of the main application, i.e. EntityMap1 would reside in the main program and EntityMap2 in the plugin. I could avoid this problem by only keeping EntityMap1 and manually modifying the generated XML.
var domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
var oldMappingXml = domainMapping.AsString();
var newMappingXml = ModifyMappings(oldMappingXml);
configuration.AddXmlString(newMappingXml);
oldMappingXml contains the XML generated by the mappings defined in the main application and ModifyMappings adds the changes required by the plugin. This is possible because the changes required by the plugins are well defined and follow the same algorithm for all plugins.
I'm am using Zend Framework.
I need to put multiple mail configurations in application.ini for Zend_Mail (using Zend_Application_Resource_Mail). Is it possible to do this using the standard classes in Zend Framework or do I need to create my own class?
I am using the latest stable version of Zend Framework.
Thanks for the answers
It does not appear to be possible to set multiple configurations for Zend_Mail with Zend_Application_Resource_Mail.
You could add the various configurations to application.ini but you will have to write your own class/functions to make the desired configuration active.
The things that are set by Zend_Application_Resource_Mail that you will have to override are Zend_Mail::setDefaultTransport($newTransport);, Zend_Mail::setDefaultReplyTo($email);, and Zend_Mail::setDefaultFrom($email);.
I tested something and found an easy thing you can do.
Set up your different configurations like this in application.ini:
mail_config.mail_test.transport.type = smtp
mail_config.mail_test.transport.host = "smtp.example.com"
mail_config.mail_test.transport.auth = login
mail_config.mail_test.transport.username = myUsername
mail_config.mail_test.transport.password = myPassword
mail_config.mail_test.defaultFrom.email = john#example.com
mail_config.mail_test.defaultFrom.name = "John Doe"
mail_config.mail_test.defaultReplyTo.email = Jane#example.com
mail_config.mail_test.defaultReplyTo.name = "Jane Doe"
Note how we are setting up options under mail_config. This will be the set of options to apply. mail_test is an example configuration. You can have multiple by setting mail_config.mail_test2, mail_config.corporate_mail, or mail_config.production etc.
Next, create an empty class that extends from Zend_Application_Resource_Mail. Preferably, it should be named and placed so it can be autoloaded.
The class:
<?php
class Application_Service_MailSettings extends Zend_Application_Resource_Mail { }
Now, here is how to override the default mail configuration easily with something else.
This example assumes you are in a controller:
// get the bootstrap, so we can get mail_config options
$bootstrap = $this->getInvokeArg('bootstrap');
$options = $bootstrap->getOption('mail_config');
// initialize the resource loader with the options from mail_config.mail_test
$mailSettings = new Application_Service_MailSettings($options['mail_test']);
$mailSettings->init(); // call init() so the settings are applied
// now the default transport, from, and reply to are set using mail_config.mail_test options.
// to use a different set of options, just do
// $mailSettings = new Application_Service_MailSettings($options['other_config');
This should accomplish what you want with very little new code.
Some months back I was working on a project to display the WCF methods and thier parameters in a dropdown. At that time I was creating a proxy using Add Service Reference and hardcoded the service interface in the code.
How can I show all the methods that are available in my WCF in a dropdown
But when I try to create the proxy dynamically to do the same, the below code doesn't work. Please help me to show only the methods that was defined by me.
// Using Dynamic Proxy Factory by Vipul Modi # Microsoft
DynamicProxyFactory factory = new DynamicProxyFactory(txtService.Text);
// endpoints.
string sContract = "";
foreach (ServiceEndpoint endpoint in factory.Endpoints)
{
sContract = endpoint.Contract.Name; //this is the service interface name, IAccountInfoService
}
DynamicProxy proxy = factory.CreateProxy(sContract);
Type proxyType = proxy.ProxyType;
MethodInfo[] methods = proxyType.GetMethods();
foreach (var method in methods)
{
//if (method.GetCustomAttributes(typeof(OperationContractAttribute), true).Length == 0)
// continue;
string methodName = method.Name;
ddlMethods.Items.Add(methodName);
}
The code commented method.GetCustomAttributes(typeof(OperationContractAttribute), true).Length doesn't work. It doesn't show any method. If I comment it out, then the result is all methods and variables. I want to restrict it to only user defined methods.
i dont know anything about DynamicProxyFactory but looking at http://blogs.msdn.com/b/vipulmodi/archive/2006/11/16/dynamic-programming-with-wcf.aspx it makes me think that
1) the proxy doesnt actually emit methods with the attribute. it doesn't seem to have a need to though i suppose you could tweak the code on your own to make that happen.
2) if you just want a list of method names, it seems you can get that from factory.Contracts
Updated: 09/02/2009 - Revised question, provided better examples, added bounty.
Hi,
I'm building a PHP application using the data mapper pattern between the database and the entities (domain objects). My question is:
What is the best way to encapsulate a commonly performed task?
For example, one common task is retrieving one or more site entities from the site mapper, and their associated (home) page entities from the page mapper. At present, I would do that like this:
$siteMapper = new Site_Mapper();
$site = $siteMapper->findByid(1);
$pageMapper = new Page_Mapper();
$site->addPage($pageMapper->findHome($site->getId()));
Now that's a fairly trivial example, but it gets more complicated in reality, as each site also has an associated locale, and the page actually has multiple revisions (although for the purposes of this task I'd only be interested in the most recent one).
I'm going to need to do this (get the site and associated home page, locale etc.) in multiple places within my application, and I cant think of the best way/place to encapsulate this task, so that I don't have to repeat it all over the place. Ideally I'd like to end up with something like this:
$someObject = new SomeClass();
$site = $someObject->someMethod(1); // or
$sites = $someObject->someOtherMethod();
Where the resulting site entities already have their associated entities created and ready for use.
The same problem occurs when saving these objects back. Say I have a site entity and associated home page entity, and they've both been modified, I have to do something like this:
$siteMapper->save($site);
$pageMapper->save($site->getHomePage());
Again, trivial, but this example is simplified. Duplication of code still applies.
In my mind it makes sense to have some sort of central object that could take care of:
Retrieving a site (or sites) and all nessessary associated entities
Creating new site entities with new associated entities
Taking a site (or sites) and saving it and all associated entities (if they've changed)
So back to my question, what should this object be?
The existing mapper object?
Something based on the repository pattern?*
Something based on the unit of work patten?*
Something else?
* I don't fully understand either of these, as you can probably guess.
Is there a standard way to approach this problem, and could someone provide a short description of how they'd implement it? I'm not looking for anyone to provide a fully working implementation, just the theory.
Thanks,
Jack
Using the repository/service pattern, your Repository classes would provide a simple CRUD interface for each of your entities, then the Service classes would be an additional layer that performs additional logic like attaching entity dependencies. The rest of your app then only utilizes the Services. Your example might look like this:
$site = $siteService->getSiteById(1); // or
$sites = $siteService->getAllSites();
Then inside the SiteService class you would have something like this:
function getSiteById($id) {
$site = $siteRepository->getSiteById($id);
foreach ($pageRepository->getPagesBySiteId($site->id) as $page)
{
$site->pages[] = $page;
}
return $site;
}
I don't know PHP that well so please excuse if there is something wrong syntactically.
[Edit: this entry attempts to address the fact that it is oftentimes easier to write custom code to directly deal with a situation than it is to try to fit the problem into a pattern.]
Patterns are nice in concept, but they don't always "map". After years of high end PHP development, we have settled on a very direct way of handling such matters. Consider this:
File: Site.php
class Site
{
public static function Select($ID)
{
//Ensure current user has access to ID
//Lookup and return data
}
public static function Insert($aData)
{
//Validate $aData
//In the event of errors, raise a ValidationError($ErrorList)
//Do whatever it is you are doing
//Return new ID
}
public static function Update($ID, $aData)
{
//Validate $aData
//In the event of errors, raise a ValidationError($ErrorList)
//Update necessary fields
}
Then, in order to call it (from anywhere), just run:
$aData = Site::Select(123);
Site::Update(123, array('FirstName' => 'New First Name'));
$ID = Site::Insert(array(...))
One thing to keep in mind about OO programming and PHP... PHP does not keep "state" between requests, so creating an object instance just to have it immediately destroyed does not often make sense.
I'd probably start by extracting the common task to a helper method somewhere, then waiting to see what the design calls for. It feels like it's too early to tell.
What would you name this method ? The name usually hints at where the method belongs.
class Page {
public $id, $title, $url;
public function __construct($id=false) {
$this->id = $id;
}
public function save() {
// ...
}
}
class Site {
public $id = '';
public $pages = array();
function __construct($id) {
$this->id = $id;
foreach ($this->getPages() as $page_id) {
$this->pages[] = new Page($page_id);
}
}
private function getPages() {
// ...
}
public function addPage($url) {
$page = ($this->pages[] = new Page());
$page->url = $url;
return $page;
}
public function save() {
foreach ($this->pages as $page) {
$page->save();
}
// ..
}
}
$site = new Site($id);
$page = $site->addPage('/');
$page->title = 'Home';
$site->save();
Make your Site object an Aggregate Root to encapsulate the complex association and ensure consistency.
Then create a SiteRepository that has the responsibility of retrieving the Site aggregate and populating its children (including all Pages).
You will not need a separate PageRepository (assuming that you don't make Page a separate Aggregate Root), and your SiteRepository should have the responsibility of retrieving the Page objects as well (in your case by using your existing Mappers).
So:
$siteRepository = new SiteRepository($myDbConfig);
$site = $siteRepository->findById(1); // will have Page children attached
And then the findById method would be responsible for also finding all Page children of the Site. This will have a similar structure to the answer CodeMonkey1 gave, however I believe you will benefit more by using the Aggregate and Repository patterns, rather than creating a specific Service for this task. Any other retrieval/querying/updating of the Site aggregate, including any of its child objects, would be done through the same SiteRepository.
Edit: Here's a short DDD Guide to help you with the terminology, although I'd really recommend reading Evans if you want the whole picture.