ASP.net Dynamic Data

David Ebbo’s screen cast is very good for show off the new ASP.net Dynamic Data. No wonder this technique alone will become one of the three major MS web solutions. It’s based on Linq to Sql, and very similar to MVC, or MV without C, because it’s still using webForms with many prebuild view templates. The folder structures are same as rails, each module should name after it’s table/model.

The dynamic field is very handy, I like RenderHint, only concern is it’s build on MS Ajax toolkit which is replaced by JQuery now.

About these ads

JSP consume PB component

Spent some time on this, here is the solution. 

 

<%
java.util.Properties props = new java.util.Properties();
props.put( "org.omg.CORBA.ORBClass", "com.sybase.CORBA.ORB" );
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(( String[] ) null, props ); 

FranksPlayGround.n_tt n_tt = FranksPlayGround.n_ttHelper.narrow( orb.string_to_object("FranksPlayGround/n_tt"));
short a = 1;
short b = 4;
short c = 3;
short sum = n_tt.add(a, b, c);
out.println(sum);
%>

This is so called API coding style. Creating PB component is easy, the important part is to ‘generate stub’ at server side. (Those Helper, Holder and Operations classes in folder “EAServer\java\classes” which n_tt inherited from ) 

The reason I back to this is we have a project needs to get a string type of return value from EAServer. Here is what we did: 

  1. Create a dst contains a dummy datawindow. (dst is from EAF)
  2. In createcontent event we call a method from component.
  3. Save this return value into dst’s message, then pass it back to JSP.
  4. JSP has to do some fancy parsing to get this value out.

Seems a lot of work, but we don’t need to do ‘generate stub’ because EAF install wizard already did this for dst. We kind of like using an empty dst passing value down to JSP. 

I can refactor this a little bit by creating a seperate service object (not component) to wrap the component call.

Strange ListBox databinding

When databinding IList to  listbox, the setter won’t be triggered when calling IList.Add(). I had to use a local variable, then set it back to view property to trigger the setter.

The listbox won’t automaticlly refresh/update the changes in IList, the stupid way of working around is set datasource to null, then set it to new value.

Looks like using CuccencyManager looks more professional? Here is MS’s instruction for CurrencyManager.

Pull up CSLA BO’s validation message

By default the CSLA BO’s brokenRulesCollection doesn’t contain child BO’s brokenrules, I tried to create a GetValidationMessages() method in MyBusinessBase class, the difficult I had was to cast and detect the generic type. Thanks to this post, I made it happen by creating an IsDerivedFromGenericType method.

I don’t need to call this:  if (child.GetType().IsSubclassOf(typeof(MyBusinessBase<>)))

Or if (child is MyBusinessBase<>)

Actually those two won’t work. This IsDerivedFromGenericType is handy.

if (IsDerivedFromGenericType(child.GetType(), typeof(MyBusinessBase<>) ) )

But it’s too complex, especially I had to call reflection to  call this GetValidationMessages recursively. Because I don’t know how to do this:

((MyBusinessBase<>)child).GetBOValidataionMessage()

Instead I had to call reflection:

        private string GetBOValidataionMessage(object v)
        {
            // Would be nice if I can cast to MyBusinessBase
            // T is an unknow onject type below, so I had to use reflection to invock method.
//            MyBusinessBase bo = (MyBusinessBase)v;
//            return bo.GetValidationMessage();

            string childValidataionMessage = "";
            // invoke method to get validation message from child BO.
            // kind of recursive call here.
            var flags =
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
            MethodInfo method = v.GetType().GetMethod("GetValidationMessage", flags);

            if (method != null)
            {
                childValidataionMessage = (string)method.Invoke(v, null);

            }
            return childValidataionMessage;
        }

In fact, it could be much easier if I just simply override the BrokenRulesCollection property. (Idea from this post.)

        public override BrokenRulesCollection BrokenRulesCollection
        {
            get
            {
                BrokenRulesCollection brokenRules = BrokenRulesCollection.CreateCollection();
                // Get root broken rules.
                brokenRules.Merge(this.ToString(), base.BrokenRulesCollection);

                foreach (var child in this.FieldManager.GetChildren())
                {
                    if (child is IEnumerable)
                    {
                        foreach (var v in (IEnumerable)child)
                        {
                                if (v is BusinessBase){
                                    brokenRules.Merge(v.ToString(), ((BusinessBase) v).BrokenRulesCollection);
                                }
                        }
                    }
                    else
                    {
                        if (child is BusinessBase)
                        {
                            brokenRules.Merge(child.ToString(), ((BusinessBase)child).BrokenRulesCollection);
                        }
                    }
                }

                return brokenRules;
            }
        }

        // BrokenRule class doesn't have an "Owner" field, which is useful in this kind of
        // multi-level object map to locate the actual error message from.
        // Fortunately, the rulename contains object name, so I can do this stupid string parse here.
        public string ExtractObjectName(string ruleName)
        {
            string result;

            // get namespace
            string spacename = this.GetType().Namespace;

            // get rid of namespace
            result = ruleName.Replace(spacename + ".", "");

            // get rid of everything after the dot
            int start = result.LastIndexOf("//") + 2;
            int end = result.IndexOf(".") ;
            result = result.Substring(start, end - start);

            return result;
        }
        public string GetValidationMessage()
        {
            StringBuilder sb = new StringBuilder();

            foreach (var x in this.BrokenRulesCollection)
            {
                 sb.AppendLine(string.Format("{0}.{1}: {2}", ExtractObjectName(x.RuleName),x.Property,  x.Description));
             }

            return sb.ToString();
        }

Watch out the data type when doing databind

We spent almost 3 hours today on trying to figure a weird problem about databinding combo box. The error just doesn’t make sense at all. What we wanted to do is very general and simple,  showing text in display area, but save key value back to object’s property.

We kept getting the selected index back to -1 when tabbing out from combo box control, debugged into combobox_selectIndexChanged method, tried to do a cast to int from comboBox.SelectedValue. The comipler didn’t allow us to do that, complained data should be less than infinity.

What? We then added a intermediate cast, first cast to int, then cast this int to short. The problem went away.

That why, short and int just don’t match automatically when databinding.

Another example of telling me that UI work is hard.

Aptana studio

I wish I had used Aptana studio (Radrails) 2 years ago, so my ruby coding experience could be more fun. This IDE is very close to Visual studio + Resharper for CSharp coding. The intelligence looks a little bit werid, might because there are too many method in ruby’s object type.

What else I like very much includes:

  1. Unite-test view, exactly same as Junit in eclipse. Once I run one of the test case, it seems no way back to the full list. Unless I re-run the class level test or select the latest test I had run.
  2. Outline view, can even launch unit-test directly. But for the method level unit-test I had to hard type in class name and method name, why no smart drop down list available?
  3. Ruby core api help window, not that help than MS one, but better than nothing.
  4. Code compete, for method, if block, etc. Same as Resharper does for CSharp.
  5. Open declaration, very useful, F3, just like Ctrl+B in R#. But it seems not very stable, I kept getting error “select text not in a ruby …”, switch to eclipse, work for a while, then got the same problem again. For some reason, my home pc just work fine. Need to figure this out someday.
  6. Looks like this aptana studio can also do php and python coding, even ajax javascript, WOW!

The annoying part for Ruby coding is environment config. For some reason my libxml didn’t work on my windows env, figured out almost whole day, then it magiclly starts to word. Still don’t know why. Probably I should copy those lib2xml.dll into windows system folder, and then copy the xml folder under $ruby\lib\ruby\site_ruby\1.8. But I was too tired of copying those folders, don’t know what one did the work. Anyway, it works now, PFM.

Those files are needed for libxml running on windows.

  1. ruby\lib\ruby\site_ruby\1.8\xml\libxml.rb
  2. ruby\lib\ruby\site_ruby\1.8\i386-msvcrt\libxml_so.so
  3. ruby\lib\ruby\site_ruby\1.8\libxml.rb

I also got a problem on installing log4r, tried gem install, update_rubygems, didn’t work, always got a loaderror. I tried “ruby -e ‘require “log4r”‘, the log4r already shonw in the list, but why still loaderror?

I ended up with download the tgz file, and run the ruby install.rb, it seems this process is doing lots of file links afterwards. So, it works. A new folder log4r was created under “ruby\lib\ruby\site_ruby\1.8\”, different than gem install.

Look into log4r, 5 methods in it, debug, info, warn, error and fatal, extact same as log4net. I remeber somewhere in my app I use a trace, it seems not a standard one.

Repository pattern in CSLA

We use Repository Pattern inside our CSLA BO to extract data access code into a separate class – repository object,  because we use interface IRepository to loose couple BO and concrete Repository object and implement “design by contract”, so BO doesn’t care which technology repository is using, either using ADO.net or Linq to SQL, or NHinbernate or Entity Framework .

The benefits of using this model include:

  • Loose coupling between BL and DAL
  • Easy to switch to different Data Access technology
  • Central place to control and switch IOC container

Updated at Feb. 09, 2009:
Found this post about the difference between DAO and Repository pattern. Yes, my model is more similar to DAO, because I was following one Repo/DAO per table rule. In fact, I’m on the progress of switching to the new Csla.ObjectFactory which is a real repository class, or, at lease, can be a repository wrapper, as Ryan did in his example.

Keyword expandsion

My post started a very interesting discuss on Alt.net newsgroup. It turns out I am still living in Jurassic. Anyway, I managed to enable this standard header for cs file to take advantage of this Keyword Expansion feature in VSS.

/***********************************************************************************
* $Author: $
* $Modtime: $
* $History: $
***********************************************************************************/

I had to set the file type in admin console to enable this feature.

My dinosaur live could become a little bit easier. I am about to relax then, until I found that TFS already obsoleted this function. Shock! Jurassic back to dark.