What if you wanted to load a template (ITemplate property) from an external user control (.ascx) file?
Yes, it is possible; there are a number of ways to do this, the one I'll talk about here is through a type converter.
You need to apply a TypeConverterAttribute to your ITemplate property where you specify a custom type converter that does the job. This type converter relies on InstanceDescriptor. Here is the code for it:
public class TemplateTypeConverter: TypeConverter
{
public override Boolean CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return ((sourceType == typeof(String)) || (base.CanConvertFrom(context, sourceType) == true));
}
public override Boolean CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return ((destinationType == typeof(InstanceDescriptor)) || (base.CanConvertTo(context, destinationType) == true));
}
public override Object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
{
Object objectFactory = value.GetType().GetField("_objectFactory", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(value);
Object builtType = objectFactory.GetType().BaseType.GetField("_builtType", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectFactory);
MethodInfo loadTemplate = typeof(TemplateTypeConverter).GetMethod("LoadTemplate");
return (new InstanceDescriptor(loadTemplate, new Object [] { "~/" + (builtType as Type).Name.Replace('_', '/').Replace("/ascx", ".ascx") }));
}
return base.ConvertTo(context, culture, value, destinationType);
}
public static ITemplate LoadTemplate(String virtualPath)
{
using (Page page = new Page())
{
return (page.LoadTemplate(virtualPath));
}
}
}
And, on your control:
public class MyControl: Control
{
[Browsable(false)]
[TypeConverter(typeof(TemplateTypeConverter))]
public ITemplate Template
{
get;
set;
}
}
This allows the following declaration:
Hope this helps!
Get it while it’s hot from here. Also read the release notes.
I’ve been working on the agenda for my presentation titled Introdução ao NHibernate
that I’ll be giving on TechDays 2010
, and I would like to request your assistance.
If you have any subject that you’d like me to talk about, you can suggest it to me. For now, I’m thinking of the following issues:
- Domain Driven Design with NHibernate
- Inheritance Mapping Strategies (Table Per Class Hierarchy, Table Per Type, Table Per Concrete Type, Mixed)
- Mappings (hbm.xml, NHibernate Attributes, Fluent NHibernate, ConfORM)
- Supported querying types (ID, HQL, LINQ, Criteria API, QueryOver, SQL)
- Entity Relationships
- Custom Types
- Caching
- Interceptors and Listeners
- Advanced Usage (Duck Typing, EntityMode Map, …)
- Other projects (NHibernate Validator, NHibernate Search, NHibernate Shards, …)
- ASP.NET Integration
- ASP.NET Dynamic Data Integration
- WCF Data Services Integration
Comments?
Once again, TechDays is at the door!
As you probably know, TechDays is Microsoft's annual event, which occurs on each country. This year, Luís Alves Martins (of Cloud Computing fame) gave me the oportunity to present one of my favorite subjects: NHibernate!
The presentation will be titled Introdução ao NHibernate. I will soon post more details, but, for now, if you live in Portugal, mark the days 20, 21 and 22 of April on your calendar, and join us there!
TechDays 2010 Portugal
Enjoy!
Type type = typeof(StringBuilder); //can be any type
ConstructorInfo ci = type.GetConstructor(new Type [ 0 ]);
Stopwatch watch = new Stopwatch();
watch.Start();
for (Int32 i = 0; i < 100; ++i)
{
StringBuilder obj = Activator.CreateInstance(type) as StringBuilder;
}
Int64 time1 = watch.ElapsedTicks;
watch.Reset();
watch.Start();
for (Int32 i = 0; i < 100; ++i)
{
StringBuilder obj = ci.Invoke(null) as StringBuilder;
}
Int64 time2 = watch.ElapsedTicks;
DynamicMethod m = new DynamicMethod(String.Empty, typeof(Object), null, type, true);
ILGenerator il = m.GetILGenerator();
il.Emit(OpCodes.Newobj, ci);
il.Emit(OpCodes.Ret);
Func<Object> creator = m.CreateDelegate(typeof(Func<Object>)) as Func<Object>;
watch.Reset();
watch.Start();
for (Int32 i = 0; i < 100; ++i)
{
StringBuilder obj = creator() as StringBuilder;
}
Int64 time3 = watch.ElapsedTicks;
Sometimes there is the need to find the control that caused the postback from outside the event handler. The following code gives you just that:
public static class PageExtensions
{
public static Control FindFiredControl(this Page page)
{
Control control = page;
Boolean asyncPost = (page.Request.Form [ "__ASYNCPOST" ] == "true");
String eventTarget = page.Request.Form [ "__EVENTTARGET" ];
if (page.IsPostBack == true)
{
//check if the postback control is not a button
if (String.IsNullOrEmpty(eventTarget) == false)
{
//all naming containers
String [] parts = eventTarget.Split('$');
foreach (String part in parts)
{
//find control on its naming container
control = control.FindControl(part);
}
}
else
{
//search all submitted form keys
foreach (String key in page.Request.Form.AllKeys.Where(k => Char.IsLetter(k [ 0 ])).ToArray())
{
//all naming containers
String [] parts = key.Split('$');
//initialize control to page on each iteration
control = page;
foreach (String part in parts)
{
//find control on its naming container
if ((part.EndsWith(".x")) || (part.EndsWith(".y")))
{
//ImageButton
control = control.FindControl(part.Substring(0, part.Length - 2));
}
else
{
//other button type
control = control.FindControl(part);
}
}
if (control is IPostBackEventHandler)
{
if (((control is ScriptManager) || (control is ScriptManagerProxy)) && (asyncPost == true))
{
//ScriptManager/ScriptManagerProxy themselves never fire postback events
continue;
}
else
{
//found firing event
break;
}
}
//clear control for next iteration
control = null;
}
}
}
return (control);
}
}
Here is the full list of all events that occur in an ASP.NET application, from the standard modules, to the page, master page, page controls and master page controls.
| What |
| When |
| HttpApplication.BeginRequest |
|
| HttpApplication.AuthenticateRequest |
|
| HttpApplication.PostAuthenticateRequest |
|
| HttpApplication.AuthorizeRequest |
|
| HttpApplication.PostAuthorizeRequest |
|
| HttpApplication.ResolveRequestCache |
|
| HttpApplication.PostResolveRequestCache |
|
| HttpApplication.MapRequestHandler |
|
| HttpApplication.PostMapRequestHandler |
|
| HttpApplication.AcquireRequestState |
|
| HttpApplication.PostAcquireRequestState |
|
| HttpApplication.PreRequestHandlerExecute |
|
| Page.FrameworkInitialize |
|
| Page.InitializeCulture |
|
| Page.OnPreInit |
|
| MasterPage.FrameworkInitialize |
|
| MasterPageControl.FrameworkInitialize |
|
| PageControl.FrameworkInitialize |
|
| MasterPageControl.OnInit |
|
| PageControl.OnInit |
|
| MasterPage.OnInit |
|
| Page.OnInit |
|
| Page.OnInitComplete |
|
| Page.LoadPageStateFromPersistenceMedium |
If IsPostBack |
| Page.LoadControlState |
If IsPostBack |
| MasterPageControl.LoadControlState |
If IsPostBack, RegisterRequiresControlState was called and control state contains elements |
| PageControl.LoadControlState |
If IsPostBack, RegisterRequiresControlState was called and control state contains elements |
| MasterPageControl.LoadViewState |
If IsPostBack and ViewState contains elements |
| PageControl.LoadViewState |
If IsPostBack and ViewState contains elements |
| Page.OnPreLoad |
|
| Page.OnLoad |
|
| MasterPage.OnLoad |
|
| MasterPageControl.OnLoad |
|
| PageControl.OnLoad |
|
| {PageControl|MasterPageControl}.OnCustomEvent |
If a custom event was fired on a control declared on the page/master page |
| {PageControl|MasterPageControl}.OnBubbleEvent |
If a custom event was fired on a control declared on the page/master page |
| {Page|MasterPage}.OnBubbleEvent |
If a custom event was fired on a control declared on the page/master page |
| Page.OnBubbleEvent |
If a custom event was fired |
| Page.OnLoadComplete |
|
| ClientCallbackControl.RaiseCallbackEvent |
If in a client callback asynchronous request |
| ClientCallbackControl.GetCallbackResult |
If in a client callback asynchronous request |
| Page.OnPreRender |
If not in an asynchronous postback |
| MasterPage.OnPreRender |
If not in an asynchronous postback |
| MasterPageControl.OnPreRender |
If Visible |
| PageControl.OnPreRender |
If Visible and not in an asynchronous postback |
| Page.OnPreRenderComplete |
If not in an asynchronous postback |
| Page.SaveControlState |
If not in an asynchronous postback and RegisterRequiresControlState is called for the page and control state contains additiona values |
| MasterPageControl.SaveControlState |
If not in an asynchronous postback and RegisterRequiresControlState is called for the master page control and control state contains additiona values |
| PageControl.SaveControlState |
If not in an asynchronous postback and RegisterRequiresControlState is called for the page control and control state contains additiona values |
| Page.SaveViewState |
If not in an asynchronous postback |
| MasterPage.SaveViewState |
If not in an asynchronous postback |
| MasterPageControl.SaveViewState |
If not in an asynchronous postback |
| PageControl.SaveViewState |
If not in an asynchronous postback |
| Page.SavePageStateToPersistenceMedium |
If not in an asynchronous postback |
| Page.OnSaveStateComplete |
If not in an asynchronous postback |
| Page.Render |
If not in an asynchronous postback |
| MasterPage.Render |
If not in an asynchronous postback |
| MasterPageControl.Render |
If Visible and not in an asynchronous postback |
| PageControl.Render |
If Visible and not in an asynchronous postback |
| Page.OnCommitTransaction |
If Transaction = Required or RequiresNew and a transaction was committed or no transaction was created |
| Page.OnAbortTransaction |
If Transaction = Required or RequiresNew and a transaction was rolled back |
| MasterPageControl.OnUnload |
|
| MasterPageControl.Dispose |
|
| PageControl.OnUnload |
|
| PageControl.Dispose |
|
| MasterPage.OnUnload |
|
| MasterPage.Dispose |
|
| Page.OnUnload |
|
| Page.Dispose |
|
| HttpApplication.PostRequestHandlerExecute |
|
| HttpApplication.ReleaseRequestState |
|
| HttpApplication.PostReleaseRequestState |
|
| HttpApplication.UpdateRequestCache |
|
| HttpApplication.PostUpdateRequestCache |
|
| HttpApplication.LogRequest |
|
| HttpApplication.PostLogRequest |
|
| HttpApplication.EndRequest |
|
| HttpApplication.PreSendRequestHeaders |
|
| HttpApplication.PreSendRequestContent |
|
My NHibernateDataSource was just a necessary step in order to build an ASP.NET Dynamic Data provider for NHibernate. I am pleased to say that it is now working! Like the NHibernateDataSource, it is only - for now - merely a proof of concept, it needs cleaning up and still misses the association metadata part, which means no links to associated entities, but list, edit, delete and insert are working fine.
If you want to try it, please download it and send me your feedback.
In order to use it, create a Dynamic Data Web Application project and change the name of the context class on the Global.asax.cs file:
model.RegisterContext(new NHibernateDataModelProvider(typeof(MyNHibernateContext)), new ContextConfiguration() { ScaffoldAllTables = true });
Then, on all of the ASPX files under the DynamicData folder, replace the EntityDataSource declaration for the NHibernateDataSource, keeping all of the properties. Add the NHibernateDataSource files to your project and add references to NHibernate and LINQ to NHibernate, from the NHContrib project, and that's it!
I wrote a NHibernateDataSource, which can be used in ASP.NET web forms applications just like their counterparts EntityDataSource and LinqDataSource.
It requires a LINQ to NHibernate NHibernateContext-derived class which specifies the queryable entities. You can get it from the NHContrib site.
I have used code from Microsoft's LINQ samples, of which I talked about on a previous post, and you can get a precompiled assembly from there.
I have not implemented the InsertParameters, DeleteParameters and UpdateParameters properties, only the WhereParameters, but it shouldn't be too difficult.
Please note that this code is merely a proof of concept, it may have problems, and it is not optimized. If you find anything in it that should be improved, drop me a line. As usual, hope you find it useful!
In order to use the new functionalities (count, projections, server paging, for instance) supplied by version 1.5 of ADO.NET Data Services (see my previous post), you must explicitly enable them on the service side.
public static void InitializeService(DataServiceConfiguration config)
{
config.EnableTypeConversion = true;
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
config.UseVerboseErrors = true;
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
}
Note that you need to use the DataServiceConfiguration instead of the IDataServiceConfiguration interface, which was the one that the wizard previously declared.
More Posts
Next page »