Nested Server Controls - controls

I've got a server control that contains nested server controls,
<uc1:ArticleControl runat="server">
<HeadLine></HeadLine>
<Blurb></Blurb>
<Body></Body>
</uc1:ArticleControl>
Code:
[ToolboxData("<{0}:ArticleControl runat=server></{0}:ArticleControl>")]
[ParseChildren(ChildrenAsProperties = true)]
public class ArticleControl : WebControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public HeadLineControl HeadLine
{
get;
set;
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public BlurbControl Blurb
{
get;
set;
}
[PersistenceMode(PersistenceMode.InnerProperty)]
public BodyControl Body
{
get;
set;
}
}
Nested control definition (applies to all nested controls):
public class HeadLineControl : ControlBase
{
public HeadLineControl() : base() { }
public HeadLineControl(Article article) : base(article) { }
Base class definition
public abstract class ControlBase : Control
{
protected Article article;
protected ControlBase() { }
protected ControlBase(Article article)
{
this.article = article;
}
The ArticleControl is responsible for writing for the individual parts of the article specified by the nested controls,
My problem is that when the Articlecontrol is created, instances of the nested server controls are created by the .NET framework using the default constructor defined for the System.Web.Ui.Control class eg:
namespace System.Web.UI
{
public class Control : IComponent, IDisposable, IParserAccessor, IUrlResolutionService, IDataBindingsAccessor, IControlBuilderAccessor, IControlDesignerAccessor, IExpressionsAccessor
{
// Summary:
// Initializes a new instance of the System.Web.UI.Control class.
public Control();
I need to call or override the default behaviour of .Net to call my Control base class constructor in stead of the default .Net defined contructor. So in short, if a new instance of HeadLineControl is created, it needs to created by the ControlBase(Article article) constuctor.
Is this possible and if possible, how do I accomplish this?

I've done this in the meanwhile as a workaround, but there must be a better way?
[PersistenceMode(PersistenceMode.InnerProperty)]
public HeadLineControl HeadLine
{
get { return null; }
set
{
this.Controls.Add(new HeadLineControl(articlePage.Article)();
}
}

Related

Entity Framework Core - EF Core 2.2 - 'Point.Boundary' is of an interface type ('IGeometry')

I am trying the new functionality with EF Core 2.2. It is based on the following article. "Announcing Entity Framework Core 2.2"
https://blogs.msdn.microsoft.com/dotnet/2018/12/04/announcing-entity-framework-core-2-2/
I installed the following Nuget package.
I added the following to my model.
using NetTopologySuite.Geometries;
//New as of EF.Core 2.2
//[Required]
//[NotMapped]
public Point Location { get; set; }
During my application startup I get the following error in my Database Context on the following line:
Database.EnsureCreated();
System.InvalidOperationException
HResult=0x80131509
Message=The property 'Point.Boundary' is of an interface type ('IGeometry'). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type, otherwise ignore the property using the NotMappedAttribute or 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Source=Microsoft.EntityFrameworkCore
You need to call UseNetTopologySuite(). Example here:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var connectionString = configuration.GetConnectionString("DefaultConnection");
optionsBuilder.UseSqlServer(connectionString, opts => opts.UseNetTopologySuite());
}
public DbSet<Test> Tests { get; set; }
}
public class Test
{
public int Id { get; set; }
public Point Location { get; set; }
}
I ran into this problem because I had a
if (!optionsBuilder.IsConfigured) around everything in my OnConfiguring. I had to remove this in order to get add-migrations to work.
As Kyle pointed out you need to call UseNetTopologySuite(), but I would call it during ConfigureServices like this:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddEntityFrameworkNpgsql()
.AddDbContext<MyDBContext>(opt =>
opt.UseNpgsql(Configuration.GetConnectionString("MyDBConnection"),
o=>o.UseNetTopologySuite()))
.BuildServiceProvider();
...
}
...
}

Windows Phone - Using generic class for PhoneApplicationPage

I have a Page which consist of AddPage.xaml and AddPage.xaml.cs. I want to create a generic class AddPage which extends from PhoneApplicationPage to outsource some repetitive code like Save or Cancel.
If I change the base class from PhoneApplicationPage to my new generic class, I get this error: Partial declarations of 'AddPage' must not specify different base classes.
To accomplish this you need to do the following.
First, create your base class
public class SaveCancelPhoneApplicationPage : PhoneApplicationPage
{
protected void Save() { ... }
protected void Cancel() { ... }
}
Then, your AddPage needs to be modified to inherit from the base class. The main places this is needed is within the code (AddPage.xaml.cs) AND within the xaml
Code:
public partial class AddPage : SaveCancelPhoneApplicationPage { ... }
Xaml:
<local:SaveCancelPhoneApplicationPage
x:Class="MyPhone.Namespace.AddPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyPhone.Namespace"
<!-- other xaml elements -->
</local:SaveCancelPhoneApplicationPage>
UPDATE: Info added based on comments
If you need to have generic like functionality and you must use the Page to do this (rather than a ViewModel) then you can still do this using generic methods
public abstract class SaveCancelPhoneApplicationPage : PhoneApplicationPage
{
protected override void OnNavigatedTo(blaa,blaa)
{
var obj = CreateMyObject();
obj.DoStuff();
}
// You should know what your objects are,
// don't make it usable by every phone dev out there
protected MyBaseObject MyObject { get; set; }
protected T GetMyObject<T>() where T : MyBaseObject
{
return MyObject as T;
}
}
public class AddPage : SaveCancelPhoneApplicationPage
{
public AddPage()
{
MyObject = new MyAddObject();
}
}
In order to outsource some functions you just declare some add class which does the common work. Having another page doesn't do that work.
public class Add
{
public bool SaveContent(string filename, string content)
{
....//some content
return true;
}
public string ViewContent(string filename)
{
string content="";
.....
return content;
}
}
Add this part of code where you thought it is redundant.
Add obj=new Add();
obj.SaveContent("myfile.txt","Hello.This is my content.");
string content("myfile.txt");
Tell me if this is what you intend or not.

NHibernate 3 Linq and IUserType

I have a table:
Page (
Id int,
Name nvarchar(50),
TemplateName varchar(50)
...
)
and it's mapped to domain model:
public class Page {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Template Template { get; set; }
}
Note that in the domain model, "Template" property is not of type "string".
The Template class is like this:
public class Template {
public string Name { get; set; }
// other properties...
}
"Templates" are loaded from file system. I have a TemplateManager class:
public class TemplateManager {
public static Template LoadTemplate(string templateName) {
// check if there's a folder named <templateName>
}
}
I can use IUserType to map the "Template" property.
public class PageMap : ClassMapping<Page> {
public PageMap() {
...
Property(c => c.Template, m => {
m.Column("TemplateName");
m.Type<TemplateUserType>();
}
}
}
public class TemplateUserType : IUserType {
public object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner)
{
var templateName = rs[names[0]].AsString();
if (!String.IsNullOrEmpty(templateName))
{
return TemplateManager.LoadTemplate(templateName);
}
return null;
}
}
Okay, so far so good. But the problem is, how can I use Template property in Linq queries?
For exmaple:
var pages = session.Query<Page>().Where(it => it.Template.Name == "MyTemplate");
I think the solution might be to write a class (say TemplatePropertyHqlGenerator) implementing IHqlGeneratorForProperty. This is the linq query extension point provided by NHibernate 3. But how to write this TemplatePropertyHqlGenerator class?
Thanks in advanced!
The IUserType interface lets you define a type which is considered atomic. That is to say, you can then perform direct comparisons between instances of the type and NHibernate will know how to translate them.
E.g. the following query would evaluate:
var template = new Template();
session.Query<Page>().Where(it => it.Template == template);
If you want to define a type which has component values which you can then manipulate, you need to implement the ICompositeUserType interface. This interface requires you define the properties of the type as atomic elements, giving NHibernate the information it needs to understand the specific properties of the type.
As a result, it's a little more complex than IUserType to implement, but it should facilitate what you want to achieve.
Here's an understandable example of implementing the interface for a Money type: http://geekswithblogs.net/opiesblog/archive/2006/08/05/87218.aspx

Why is an item in the ViewBag not propagated to the _Layout page?

I have a SiteNavigation class that is being updated in the Initialize event of my base controller e.g.
[Serializable]
public class SiteNavigation
{
public SiteNavigation()
{
IsSummarySelected = true;
}
public Model.Dtos.Folder[] Folders { get; set; }
public bool IsSummarySelected { get; set; }
}
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
var siteNavigation = new SiteNavigation();
siteNavigation.Folders = GetMeMyFolders() as Folder[];
ViewBag.SiteNavigation = siteNavigation;
}
and in the controller the IsSummarySelected property is changed to this value.
ViewBag.SiteNavigation.IsSummarySelected = false;
When I access the property in the _Layout file with this line of code, the value is ALWAYS true. It's as if the nav object is being New'd up again and the constructor is setting it to true.
#if (ViewBag.SiteNavigation.IsSummarySelected)
I've tried casting the nav object back to a variable and setting the property that way too, no dice. Any help would be appreciated.
Call me baffled!
Thank you,
Stephen
I just copy pasted your code into my sample mvc project, and changing IsSummarySelected in my action correctly was reflected in the _Layout file. Are you certain your controller's assignment is getting hit, and you're not reassigning it afterwards somewhere else?
Edit: Your issues are an example of why I think it's a bad idea to use ViewBag for anything other than a localized quick fix. Debugging dynamic global objects is no fun. Refactoring suggestion: Make a site Navigation property in your base controller
SiteNavigation siteNavigation;
public SiteNavigation SiteNavigation
{
get
{
return siteNavigation;
}
set
{
siteNavigation = value;
}
}
and replace all references to ViewBag.SiteNavigation with this. Then create a custom WebViewPage and put in it.
public SiteNavigation SiteNavigation
{
get
{
return ((BaseController)ViewContext.Controller).SiteNavigation;
}
}
This won't fix your problem, but now you can just stick breakpoints on the get and set properties of SiteNavigation, and it should be very easy to debug your issue now.
I fill my TempData["SplitterIsCollapsed"] when Filters are invoked then via OnResultExecuting method. Additionally i fetch a property state from my UserContext class, which is registered only once per session: builder.RegisterType().As().CacheInSession(); .
Basic info: I use DependcyInjection!
Assignment of the Filter to the Controller:
Controller:
[LayoutTempData]
public class HomeController : Controller
{
//....
}
FilterAttribute class:
namespace MyProject.Web.Infrastructure.Filters
{
public class LayoutTempDataAttribute : ActionFilterAttribute
{
private readonly IUserContext _userContext;
public LayoutTempDataAttribute()
{
_userContext = DependencyResolver.Current.GetService<IUserContext>();
}
public override void OnResultExecuting(ResultExecutingContext context)
{
if (context.Controller.TempData.ContainsKey("SplitterIsCollapsed"))
context.Controller.TempData["SplitterIsCollapsed"] = _userContext.LayoutInformation.SplitterIsCollapsed;
else
context.Controller.TempData.Add("SplitterIsCollapsed", _userContext.LayoutInformation.SplitterIsCollapsed);
}
}
}
The Splitter part of the _Layout.cshtml looks like:
#{Html.Telerik().Splitter().Name("Splitter1")
.Panes(panes =>
{
panes.Add()
.Size("300px")
.Collapsible(true)
.Collapsed((bool)TempData["SplitterIsCollapsed"])
.Content(<div>asdfasdf</div>);
panes.Add()
.Collapsible(false)
.Scrollable(false)
.Content(<div>content2</div>);
})
.Render();
}

Can Ninject resolve abstract dependencies after the object is initialised?

Does anyone know if it's possible to use Ninject to resolve any unresolved abstract dependencies outside of the instantiation process? I've just been looking into constructor injection vs property/method/field injection, but it looks to me as though Ninject is still expecting to be the creator of the type using the IKernel.Get<>() method.
Basically, we're using MVC3 to build our product, and we've come up against a situation where we want the default ModelBinder to map form values to an instance of the object, and then be able to call a method on the submitted ViewModel that is dependent on an abstract interface e.g.
public class InviteFriend {
[Required]
public string EmailAddress { get; set; }
public void Execute() {
var user = IUserRepository.GetUser(this.EmailAddress);
if (user == null) {
IUserRepository.SaveInvite(this.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
SmtpClient.Send(toSend);
}
}
where the controller action would receive InviteFriend as the method argument. We want Ninject to be able to resolve that IUserRepository dependency, but I can't quite work out how to since the object itself is instantiated by the MVC ModelBinder rather than Ninject IKernel.Get<>().
Maybe the solution is a Ninject-based ModelBinder, or does that seem a really bad idea?
EDIT TO ADD: After the comments below, I realise that my hastily mocked-up code sample doesn't really reflect what we're facing. I've updated the code sample to reflect that the logic for InviteFriend.Execute() is more complex than just calling a method on one repository. Potentially, this is logic representing a discrete task that could co-ordinate interactions between multiple different domain objects and multiple repositories. The repositories are defined abstractly, and ideally would be resolved by Ninject.
I think what you are looking for is somewhat the following scenario:
public class InviteFriend {
[Required]
public string EmailAddress { get; set; }
// More information
}
public interface ICommand {
void Execute();
}
public class InviteFriendCommand : ICommand
{
public InviteFriend(InviteFriend info, IUserRepository userRepo, IMailSender mailSender) {
this.inviteFriend = info;
this.userRepo = userRepo;
this.mailSender = mailSender;
}
public void Execute() {
var user = this.userRepo.GetUser(this.inviteFriend.EmailAddress);
if (user == null) {
this.userRepo.SaveInvite(this.inviteFriend.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
this.mailSender.Send(toSend);
}
}
public interface ICommandFactory {
ICommand CreateInviteFriendCommand(InviteFriend info);
}
public class CommandFactory {
public CommandFactory(IResolutionRoot resolutionRoot) {
this.resolutionRoot = resolutionRoot;
}
ICommand CreateInviteFriendCommand(InviteFriend info) {
this.resolutionRoot.Get<InviteFriendCommand>(new ConstructorArgument("info", info));
}
}
public class YourController {
// Somewhere
var command = this.commandFactory.CreateInviteFriendCommand(info);
command.Execute();
}
public class YourModule : NinjectModule {
override Load() {
Bind<IUserRepository>().To<UserRepo>().InRequestScope();
Bind<ICommandFactory>().To<CommandFactory>().InRequestScope();
Bind<InviteFriendCommand>().ToSelf().InRequestScope();
}
}
Forgive me when you need to tweak it a bit. I hacked it together with my out of brain compiler ;)
Thank you for all your comments, but I've subsequently found the information I was looking for.
The answer is that it is possible to inject dependencies post-instantiation with Ninject. The solution is as follows:
public class InviteFriend {
[Inject]
public IUserRepository UserRepo { get; set; }
[Required]
public string EmailAddress { get; set; }
public void Execute() {
var user = UserRepo.GetUser(this.EmailAddress);
if (user == null) {
UserRepo.SaveInvite(this.EmailAddress);
}
MailMessage toSend = new MailMessage(); // Obviously some logic to prepare the body, subject and other mail properties
SmtpClient.Send(toSend);
}
}
With client code then using the Ninject kernel as follows:
IKernel container = new StandardKernel(new ModuleWithMyBindings());
container.Inject(instanceOfInviteFriend);
The code itself is a bit more sophisticated than that i.e. I'm not instantiating a new IKernel each time I need it.
I realise that this is architecturally less pure than some of the suggestions put forward in comments, but in the spirit of YAGNI, this is good enough for now and we can always refactor later on with some of the good suggestions in Daniel's answer. However, this was a question about the capabilities of Ninject rather than an architectural review question, and this is what I consider the answer to my own question :)

Resources