268
I Use This!
Very Low Activity

News

Analyzed about 11 hours ago. based on code collected 1 day ago.
Posted over 16 years ago by [email protected] (Markus Zywitza)
One of the feature requests that I hear most often from my users that they want a search function for the grids. I then show them a search form where they can specify field and values exactly. Most often, I then hear: "No, I meant a search field. I ... [More] enter some text and the software shows all relevant entries." I usually answer by asking whether it should also save the climate and overcome poverty or if simple mindreading is sufficient. Ok, but last night I had an idea how searching with a single textfield interface can be accomplished without redeveloping that nasty thing for each view. I use the Castle stack for .Net for my applications, which means that my entities are created with Castle ActiveRecord and displayed in MonoRail web applications. The idea works like this: There is only one who knows which properties must be included into the search and this the developer that created the entities. Therefore we need some mechanism to specify the searchable properties. My idea was adding a Searchable attribute to the ActiveRecord classes' properties that need to be included in such searches: [ActiveRecord] public class Entity : ActiveRecordBase<Entity> { private int id; private string name; private string entityDesc; private string internalName; [PrimaryKey] public int Id { get { return id; } set { id = value; } } [Searchable][Property] public string Name { get { return name; } set { name = value; } } [Searchable(FriendlyName = "Description")][Property] public string EntityDesc { get { return entityDesc; } set { entityDesc = value; } } [Property] public string InternalName { get { return internalName; } set { internalName = value; } } } The Searchable takes an optional parameter, FriendlyName that allows to specify a localized or other, more user-friendly name. The attribute can be applied to both properties and relations. If applied to a relation attribute (BelongsTo, HasMany, HasAndBelongsToMany etc.) the properties tagged in that type will be added to the search as well. Then there is a SearchMediator, which will create a NHibernate Criteria Query that will check for every search term whether it can be parsed by the datatype of a tagged property and adds it to the query if this is the case. The code below sketches how the query could be created: public static T[] Search(string text) { string[] words = text.Split(); DetachedCriteria criteria = DetachedCriteria.For<T>(); foreach (string word in words) { Disjunction group = Expression.Disjunction(); foreach (PropertyInfo info in typeof (T).GetProperties()) { if (info.GetCustomAttributes(typeof (SearchableAttribute), true).Length > 0) group.Add(Expression.Like(info.Name, word, MatchMode.Anywhere)); } criteria.Add(group); } return ActiveRecordMediator<T>.FindAll(criteria); } This can be extended by many means. Examples include: Allowing propertyName:searchTerm to narrow search to a specific property by its name or friendly name.Allowing other operators than the colon like price>10.00 or name!FooAdd globbing to specify whether exact matches or all matches should be foundSpecify the MatchMode behavior for string properties as part of SearchableAttributeUsing that mechanism, I can add searching to almost any entity similar to validation. What do you think, would such a Search component benefit the Castle Framework?That is only some thoughts. I didn't start implementing anything yet. However, anyone interested in helping is welcome, of course. [Less]
Posted over 16 years ago
I had to compare different styles of error handling approaches, and I automatically compared the ideal, Castle Style errors, to the nasty, Mystery HRESUTL of the Week. But what does Castle Style errors means? Let us take a look at a few of them. When ... [More] an module that was registered before the MonoRail http module had thrown an exception: throw new Exception( "An exception happened on Global application or on a module that run before MonoRail's module. " + "MonoRail will not be initialized and further requests are going to fail. " + "Fix the cause of the error reported below.", context.Context.Error); Or what happens when you are trying to access an ActiveRecord class when you didn't initialize it properly? String.Format("An ActiveRecord class ({0}) was used but the framework seems not " + "properly initialized. Did you forget about ActiveRecordStarter.Initialize() ?", type.FullName); And: String.Format("You have accessed an ActiveRecord class that wasn't properly initialized. " + "The only explanation is that the call to ActiveRecordStarter.Initialize() didn't include {0} class", type.FullName); The common theme for those errors is that they are: Descriptive Show all the relevant information Suggest a probable solution Save time I added the following exception: throw new ActiveRecordException(String.Format( "You can't use [Property] on {0}.{1} because {2} is an active record class, did you mean to use BelongTo?", model.Property.DeclaringType.Name, model.Property.Name, propertyType.FullName)); I added that after I spent half an hour trying to figure out why something was wrong. Since then, I keep running into this exception, and then it is a "slap on the head, replace [Property] with [BelongsTo] and move on". And that is me, who wrote this bloody annoying exception that I am supposed to already know and avoid triggering. I can't imagine how many hours this exception alone has saved, just for my team. In fact, when I gave a talk at DevTeach about MonoRail, I have literally built the entire demo by just following the instructions from the exceptions. That is good error handling, and that is what I consider as the standard that you should aspire to. Anything less than that is cause for anger, anxiety and angst. Do save yourself the ulcer, put in the best errors you can. [Less]
Posted almost 17 years ago by [email protected] (mausch)
Warning: the following code has become obsolete since the release of Castle RC3. I'll update as soon as I can. The concepts still apply, though. Recently I've been writing an app using Castle Windsor. While I was writing the service classes, the ... [More] following problem came up: I don't want my services' consumers catching Dao exceptions. I'm using ActiveRecord to persist domain objects, but it could have been directly NHibernate, or iBatis. Either way, whoever uses the service classes should be ignorant about persistance details. Suppose the service interface looks like this:public interface ISomeService { void ProvideService(); }and its implementation lets an internal exception pass, which we could model like this to make things simple:public class SomeService : ISomeService { public void ProvideService() {    throw new InternalException();   } } public class InternalException : ApplicationException {}Now we'd like to translate InternalException into an ExternalException, which is a service-level exception. We could manually catch InternalException in every method of SomeService, but that's annoying.Let's use Windsor instead. We need three components: the exception translator (which says what external exception corresponds to each internal exception), the interceptor (which actually does the try..catch) and a contributor (which installs the interceptor and translator).First, let's write a test that should pass when we finish installing all three components:[TestFixture] public class ExceptionTranslatorTests {   [Test] [ExpectedException(typeof (ExternalException), "1")]   public void ExceptionIsTranslated() { IWindsorContainer container = new WindsorContainer(); container.AddComponent("service", typeof (ISomeService), typeof (SomeService)); ISomeService svc = container.Resolve<ISomeService>(); svc.ProvideService();   } } public class ExternalException : ApplicationException { public ExternalException(string message) : base(message) {}   public ExternalException() {}   public ExternalException(string message, Exception innerException) : base(message, innerException) {} }If we run this test now, it will fail, since the exception thrown by ProvideService() is still InternalException instead of the expected ExternalException.Now let's build the translator:public interface IExceptionTranslator { Exception translate(Exception e); } public class SomeExceptionTranslator : IExceptionTranslator { public Exception translate(Exception e) {    return new ExternalException("1", e);   } }Simple, no? Just make sure you wrap the original exception, so you don't lose stack information and stuff.Now for the generic interceptor:public class ExceptionTranslationInterceptor<T> : IMethodInterceptor where T : IExceptionTranslator { private T translator;   public ExceptionTranslationInterceptor(T translator) {    this.translator = translator;   }   public object Intercept(IMethodInvocation invocation, params object[] args) {   try {      return invocation.Proceed(args);     } catch (Exception e) {       throw translator.translate(e); }   } }Notice that the actual translation logic will be injected by Windsor into the interceptor. Oh, and make sure theIMethodInterceptor you implement is the one in Castle.Core.Interceptor, not the one in AopAlliance.Intercept.You may wonder why the interceptor takes <T>, you'll see why in a second when we build the contributor:public class ExceptionTranslatorContributor<T, T2> : IContributeComponentModelConstruction where T2 : IExceptionTranslator {   public void ProcessModel(IKernel kernel, ComponentModel model) {    if (typeof (T).IsAssignableFrom(model.Implementation)) {     kernel.AddComponent(typeof (T2).ToString(), typeof (T2));       kernel.AddComponent(string.Format("ExceptionTranslationInterceptor<{0}>", typeof(T2)), typeof(ExceptionTranslationInterceptor<T2>));       model.Interceptors.Add(new InterceptorReference(typeof (ExceptionTranslationInterceptor<T2>))); } } } This contributor takes two types: T, which is the service to intercept, and T2, which is the IExceptionTranslator. It installs the translator and the corresponding interceptor as components, then it installs the interceptor as such. By making the interceptor and the contributor generic, we can easily associate different translators for different services, just by setting up the contributor in the container, like this:[TestFixture] public class ExceptionTranslatorTests {   [Test] [ExpectedException(typeof (ExternalException), "1")]   public void ExceptionIsTranslated() { IWindsorContainer container = new WindsorContainer(); container.Kernel.ComponentModelBuilder.AddContributor(new ExceptionTranslatorContributor<SomeService, SomeExceptionTranslator>()); container.AddComponent("service", typeof (ISomeService), typeof (SomeService)); ISomeService svc = container.Resolve<ISomeService>(); svc.ProvideService();   } } And now the test passes!Full code shown here is available here. [Less]
Posted almost 17 years ago
Overriding component parameters when using the Castle.MicorKernel turned out to be kinda weird. Anyway, here's one way to do it. IoC.Container.Kernel.RemoveComponent("ComponentA"); IoC.Container.Kernel.AddComponentInstance( "ComponentA", typeof ... [More] (ComponentA), new ComponentA("Customer parameter for testing.")); I needed to override the parameter value of ComponentA for some unit tests. The parameter is normally set in the configuration file. After trying a few different approaches, I ended up with the code above. It's more of an end to end unit test, and as such ComponentA will be resolved as a result of another Component being resolved. [Less]
Posted over 17 years ago
Using Castle monorail with windsor, I setup the logging facility and followed the IoC of concept parameters for optional components. I noticed the base Controller had Logger property and assumed that windsor would handle it from there. However, my ... [More] controller always had the NullLogger as the ILogger property. The base Controller class doesn't have a setter for the Logger property. Still not sure why that is, also the property is not virtual. I should submit a patch for this. Anyway, one solution is to create a new property Logger in your own Controller with a getter and setter thus allowing windsor to set the Logger when the Controller is created. public abstract class BaseSiteController : ARSmartDispatcherController { private ILogger _logger = new NullLogger(); public new virtual ILogger Logger { get { return _logger; } set { _logger = value; } } } [Less]
Posted over 17 years ago
I wanted to create castle project template for SharpDevelop, I ran into a few issues, some I found a way to fix, some I didn't. One thing that I needed to do was add a project reference to a dll that was not in the GAC, to do this the HintPath ... [More] attribute can be used on the Reference element. <Reference Include="Castle.Core" HintPath="c:\castlebin\Castle.Core.dll"/> Secondly, I wanted to set the debug options to allow cassini debugging. I found a way to set these options but I didn't find a way to dynamically insert the project name/dll into the command line options. In the PropertyGroup element you can add the following to set these options. Note the ${ProjectName} string is not replaced with the project name. <DebugOptions> <StartAction>Program</StartAction> <StartProgram>c:\program files\cassini\CassiniWebServer2.exe</StartProgram> <StartArguments>C:\Documents and Settings\Dusty\My Documents\SharpDevelop Projects\${ProjectName} 8080 "/${ProjectName}"</StartArguments> </DebugOptions> So I guess there are still two main problems with this setup. First you have to know the path of any dll's that are not installed in the GAC. And if you want to reference the project name in the debug options, it doesn't look like there is a way to do that. But for setting up personal project templates these things may be useful. [Less]
Posted over 17 years ago
While setting up exception chaining on monorail, I wanted to use the Flash properties to store the LastException for next request, an error page. This by default doesn't work if the exception happens outside of the ... [More] Castle.MonoRail.Framework.MonoRailHttpHandler.Process method. This is because the Flash variables don't get saved until after this method. One note here, the Process method is wrapped in a try, finally block and the Flash properties will be saved in the case of an exception on the Process method, some additional checking in the exception handler may be needed to catch this. Anyway, I added the following line to my last handler and the Flash properties are working great. context.Session[Flash.FlashKey] = context.Flash; Secondly, I wanted to redirect to different views based on the exception, which I wasn't able to do. The reason was that the asp.net framework noticed the exception an handled according, not what I wanted. The way around this is to clear the error using the Server.ClearError() method before redirecting. context.UnderlyingContext.Server.ClearError(); [Less]
Posted almost 18 years ago
[HasMany(typeof(MyObject), "object_id", "objecttable", RelationType = RelationType.Map, Cascade = ManyRelationCascadeEnum.All, CustomAccess = Generics.Access, Lazy = true, Index = "name-of-key-column-in-objecttable", IndexType = "System.String")] ... [More] public IDictionary Objects {...} Castle Project :: View topic - Dictionary and RelationType.Map, Index, IndexType [Less]
Posted almost 18 years ago
fValidate on web archive - Looking for fValidate info, try the archived fValidate website.