I'm trying to upgrade the my Kentico Cloud SDK from v7 to v10. Before I was just creating a new instance of the DeliveryClient to build a service of my site's urls to resolve and then pass that to my CustomContentLinkUrlResolver e.g.
services.AddSingleton<NavigationProvider>(c => new NavigationProvider(new DeliveryClient(deliveryOptions) {
CodeFirstModelProvider = { TypeProvider = new CustomTypeProvider() }
}, cache));
services.AddSingleton<IDeliveryClient>(c => new CachedDeliveryClient(projectOptions, cache)
{
CodeFirstModelProvider = { TypeProvider = new CustomTypeProvider() },
ContentLinkUrlResolver = new CustomContentLinkUrlResolver(c.GetRequiredService<NavigationProvider>())
});
So I have this circular dependency where the DeliveryClient depends on the CustomContentLinkUrlResolver which depends on the DeliveryClient.
The frustrating part is the ResolveLinkUrl(ContentLink link) method doesn't have the information I need to resolve urls, because the urls are defined by the taxonomy of an item which is unavailable in ContentLink which means I have to do another lookup of the item to get the taxonomy.
I don't know how to get around CustomContentLinkUrlResolver having a dependency on DeliveryClient.
I hope I got your situation right:
You call DeliveryClient instantiated as a singleton in dependency injection container and this client is using CustomContentLinkUrlResolver which needs to make another API call to get information to the item taxonomy, but you want to use a different instance of DeliveryClient to avoid circular dependency on the singleton implementation.
In that case, it is possible to create a new instance of DeliveryClient by using DeliveryClientBuilder introduced in version 8.
// Sample resolver implementation
public class CustomContentLinkUrlResolver : IContentLinkUrlResolver
{
public string ResolveLinkUrl(ContentLink link)
{
IDeliveryClient client = DeliveryClientBuilder.WithProjectId("<YOUR_PROJECT_ID>").Build();
// Do the call
// return URL
}
}
Related
I am using an in-house construct library which is responsible for creating an ECS cluster and service alongside the task definition to run. Everything is happening inside itself, and after creating all these resources in its constructor, does not return anything (its just a function call provided by that library). I pass my App object as the scope of that stack when I call that function, so besides my stack I created within my CDK code same App object holds both stacks.
My point here in order to pass the name of the task definition to use in my lambda (to be passed as a parameter to RunTask AWS SDK call to start a task), I need the name/ref of that task definition which was created in the in-house construct library.
I wonder what's the best way to access such resources in AWS CDK. Is it ok to use class members as getters to access these resources or ConstructNode is a proper way to handle such a case?
You can add properties to your CDK stacks and reference those in others. Behind the scenes each CloudFormation Stack creates outputs and parameters. (This may not always be ideal, as my particular use case made it more difficult to refactor and update the application.)
// Pipeline contains an ECR repository we'd like to reference elsewhere
public class PipelineStack : Stack
{
public IRepository EcrRepository { get; }
public PipelineStack(Construct parent, string id, IPipelineStackProps props)
: base(parent, id, props)
{
EcrRepository = new Repository(
this,
"EcrRepository",
new RepositoryProps
{
// props
});
// rest of stack...
}
}
// Given IApiStackProps similar to:
public interface IApiStackProps : IStackProps
{
IRepository Repository { get; }
}
// Now we'd like to load an ECR task found in that referenced repository
public class ApiStack : Stack
{
public ApiStack(Construct parent, string id, IApiStackProps props)
: base(parent, id, props)
{
var repo = Repository.FromRepositoryName(
this,
"EcrRepository",
props.Repository.RepositoryName);
var container = new ContainerDefinition(
this,
"ApiContainer",
new ContainerDefinitionProps
{
TaskDefinition = taskDef,
Image = ContainerImage.FromEcrRepository(repo, imageTag.ValueAsString),
});
// rest of stack...
}
}
This allows you to create two stacks quite simply sharing resources:
var app = new App(new AppProps());
var pipelineStack = new PipelineStack(app, "ExamplePipeline", new PipelineStackProps
{
// some props...
});
new ApiStack(app, apiStackName, new ApiStackProps
{
Repository = pipelineStack.EcrRepository,
});
This led me to create a series of stacks like the following diagram with the topmost stacks requiring resources from below:
From personal experience I'd recommend staying away from too many inter-stack dependencies for the aforementioned reasons. Where possible move "shared" or referenced resources into a base stack you can extend (.NET's Lazy<T> made this easy to only create resources when acessed). With this shared base approach the number of stacks will likely decrease and allow for easier long-term support and updating:
Unfortunately I do not have a good public example of this second approach, however, the code snippets above are from my ECS CDK example repo which shares a lot between stacks.
I understand the benefit or repository pattern but I just can't understand in Symfony3 Doctrine there are Doctrine\ORM\EntityManager and \Doctrine\ORM\EntityRepository
What are the difference between the two?
Is repository should be injected to controller or entity manager?
Edit
The correct question should be: What's the proper way to access a repository from a controller?
Should a repository be injected to a controller as a service?
Should a repository be injected to another service as a service?
Should entity manager contain any query at all?
Edit
The correct question should be: should a service contain a query at all? Which #MateuszSip already explained, it could be done by injecting Entity Manager
Should a custom function like getAvailableManagers be put in
repository or services? (Where manager is a repository and there
are some logic in determining available manager)
How about a more generic function like findAllManager, should it be in repository or entity manager?
Currently I'm using Symfony3. Thank you very much
Cheers,
Edit
Talking to #MateuszSip (thanks mate), I decided to make my question clearer with an example below. Please note that below code are not representing real problem
controller
Class ManagementController
{
public function assignManager($projectType)
{
// Grabbing a service
$s = $this->get('mycompany_management_management_service')
$managers = $s->findAvailableManagers();
$managers = $s->checkCapability($managers, $projectType);
return $managers
}
}
repository
class ManagerRepository extends \Doctrine\ORM\EntityRepository
{
public function findAvailableManagers()
{
...
return $managers
}
public function checkCapability($managers, $type)
{
...
return $capableManagers
}
}
services
class ManagementService
{
... I am not sure what should be here.
}
EntityManager is used to manage doctrine-related objects, so:
you can persist an entity object (it's now managed by doctrine, and ready to save)
you can remove an entity object (so it'll be deleted later)
you can flush, and it'll trigger pending operations
you can get a repository (to get objects you'll need) or use a generic api to get an object by a primary key
etc.
It's a class that manages a state of objects and their relation to the database.
Repository is a pattern that standarizes an access to the entites.
If your app is complex, you should inject a separate service(s) to your controller. So there's a UserSaver service (as an example) that use entityManager to create/update a user and UserFinder (or something well-named) using UserRepository which's responsible of fetching user by defined criterias.
You can create a query using entity manager, but em itself cannot contain queries.
In my opinion, define a method inside a service, and a corresponding method in your UserRepository. At this moment, all of what you want should be fetched by a database, but it can change later.
In repository. Methods like: findByRole(role=manager), findIsActive, findOneBySecurityNumber relies to a repository.
So I've build a WebAPI from scratch, including some best practices that I've found online such as Dependency Injection and Domain<->DTO mapping using auto mapper etc.
My API Controllers now look similar to this
public MyController(IMapper mapper)
{
}
and AutoMapper Registry:
public AutoMapperRegistry()
{
var profiles = from t in typeof(AutoMapperRegistry).Assembly.GetTypes()
where typeof(Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}
I'm also building a few test cases, implementing MOQ, and this is where i feel a little unsure. whenever calling my controllers, I need to pass in an IMapper like this:
var mockMapper = new Mock<IMapper>();
var controller = new MyController(mockMapper.Object);
But then, how do i configure the IMapper to have the correct mappings? It feels redundant to recreate the same logic I've already created before to configure the Mapper. so I am wondering what is the recommended approach to do this?
That's pretty simple: if you mock IMapper and imagine it as a fully abstract concept of mapping data from one object to another, then you have to treat is an abstraction and not imply there's a real automapper behind it.
First you should not register any existing profile at all, you should instead setup IMapper.Map method to return specific object when given another object.
So for each profile used for specific method you have to do a setup, looking approximately like this:
var mockMapper = new Mock<IMapper>();
mockMapper.Setup(x => x.Map<DestinationClass>(It.IsAny<SourceClass>()))
.Returns((SourceClass source) =>
{
// abstract mapping function code here, return instance of DestinationClass
});
In this case, your test knows nothing about actual IMapper implementation - it just uses it methods to get the data you expect from actual IMapper implementation to receive.
This might me another solution
//auto mapper configuration
var mockMapper = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfile()); //your automapperprofile
});
var mapper = mockMapper.CreateMapper();
And then call then controller like so
var controller = new YourController(imapper:mapper,..otherobjects..);
This way it will serve the purpose or else if you create mock object for IMapper then it will return what you ask it to return.
I'm trying to setup a brand new Sitecore 7.2 website and I'm looking to integrate MVC 5, Glass Mapper and Microsoft Unity as a DI container and Sitecore doesn't want to play very nice.
My scenario is this:
Got a Web project called PoC.Quotes.Web - this will contain only CSS, HTML and any other assets, no controllers
Got a class library project called PoC.Quotes.Controllers - this only contains controllers
Got a class library project called PoC.Quotes.DataLayer - this contain a interface ISitecoreRepository and it's concrete implementation SitecoreRepository
The SitecoreRepository class has a constructor that receives 1 single parameter, the Glass Mapper Context, and one of my controllers receives 1 single parameter in the constructor...the ISitecoreRepository.
Sitecore repository class:
public class SitecoreRepository : ISitecoreRepository
{
ISitecoreContext sitecoreContext = null;
public SitecoreRepository(ISitecoreContext context)
{
this.sitecoreContext = context;
}
}
Controller class:
public class HomeController : Controller
{
private ISitecoreRepository _repository;
public HomeController(ISitecoreRepository repository)
{
this._repository = repository;
}
}
Every time I run the project Sitecore throws an error saying that it cannot create a controller of type (PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers). I guess it shows the fully qualified name because that's how I set it up in the controller rendering.
First problem is the controller constructor parameter. I took it out and use this statement to get the instance for the repository:
System.Web.Mvc.DependencyResolver.Current.GetService<ISitecoreRepository>();
The result is null, because the class SitecoreRepository is only having 1 constructor with 1 parameter and it won't get instantiated. Once I get that parameter out of the question too, then all works great.
However, to me this kinda defies the purpose of having a DI container.
I've tried looking at Castle Windsor, but although there is more documentation online, nothing works as I'm getting similar issues.
It is a bit annoying because if I run a similar test in a basic MVC 5 app (I did that just to be sure I'm not going mad), all works fine in less than 5 minutes.
Any ideas?
Edit:
In an interesting twist, after a few good hours spent on this issue, I've noticed that actually either Unity or Windsor containers work fine with one limitation...a big one.
In my controller rendering I've set the controller property as the fully qualified name of the controller:
PoC.Quotes.Controllers.HomeController, PoC.Quotes.Controllers
However, if I go in Sitecore and change that property to just Home, by magic all is good. I've even tried the interim version of using PoC.Quotes.Controllers.Home but still get an error, a different one mind you.
Not sure if I'm doing something wrong but it feels a bit odd.
Any ideas how to get this fixed?
While I can't tell how your registrations are configured, it sounds like you might be better off with a controller factory. The example is Windsor but you could easily swap in Unity. So that you're not modifying the Global.asax, you can also use WebActivatorEx to wire up the bootstrapping startup.
Bootstrapper
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Site.Website.Cms.WindsorConfig), "RegisterComponents")]`
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(Site.Website.Cms.WindsorConfig), "ReleaseComponents")]
/// <summary>
/// Provides a bootstrapping and resolving hook for dependency resolution for MVC, Web API, and service locator.
/// </summary>
public static class WindsorConfig
{
private static Lazy<IWindsorContainer> _container;
static WindsorConfig()
{
_container = new Lazy<IWindsorContainer>(() => BuildContainer());
}
public static IWindsorContainer WindsorContainer
{
get
{
return _container.Value;
}
}
/// <summary>
/// Generates and configures the container when the application is started.
/// </summary>
public static void RegisterComponents()
{
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(WindsorContainer));
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorControllerActivator(WindsorContainer));
}
/// <summary>
/// Disposes of the container when the application is shut down.
/// </summary>
public static void ReleaseComponents()
{
WindsorContainer.Dispose();
}
}
Controller Factory
/// <summary>
/// Provides controller dependency resolving for ASP.NET MVC controllers.
/// </summary>
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container)
{
if (container == null) throw new ArgumentNullException("container");
this._container = container;
}
public override void ReleaseController(IController controller)
{
this._container.Release(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)this._container.Resolve(controllerType);
}
}
Spent a considerable amount of time on this and managed to come up with a solution. It was a bit long to write in here so I've put it on a blog post http://agooddayforscience.blogspot.co.uk/2015/10/sitecore-multi-tenancy-and-di-containers.html
Basically it wasn't an issue with Unity or other DI container, it was around how Sitecore handles fully qualified names. Yes, I know that ideally you don't want to use those but to follow the MVC pattern, but I've explained more in the blog post around why use fully qualified names.
As a high level explanation the problem resides in 2 Sitecore classes ControllerRunner and SitecoreControllerFactory. Both classes contain some methods that identify the fully qualified name and use reflection to call the parameter-less constructor to instantiate a new instance. The fix I've applied overrides these methods to call the controller factory regardless.
Thanks for all the help provided.
Andrei
I register components in global.asax.I resolve in try block in every web method and release in finally block. I created a wrapper for container so that it is called directly only during registration. Web methods call this wrapper to resolve and release components. This try finally adds a lot of boilerplate code.
Am I doing right? If not how should I do it? I am using Castle Windsor.
[WebMethod]
public void SomeMethod()
{
ISomeComponent c = null
try
{
c = myContainer.ResolveSomeComponent();
c.Method();
}
finally
{
myContainer.Release(c);
}
}
I have found the solution. As it turns out I can configure my components as Per Web Request and then I don't have to release them because they will be automatically released at the end of request.
You can find details in this article: http://devlicio.us/blogs/krzysztof_kozmic/archive/2010/08/27/must-i-release-everything-when-using-windsor.aspx