Custom SmartParts

Posted on was a question on how to create custom smart parts for SalesLogix Web Client. Now I like custom smart parts, so much so that I find myself eventually going there quite often. You might say this is counter intuitive as you should just ‘Set it and forget it’ with the OTB form editor and data binding capabilities. This is where I somewhat deviate on that thought process. I find that the forms editor makes for me anyways a great prototype starting point where you can get the UI set up just so. But after its setup I find myself happily in Visual Studio making edits to clean up the generated code or have the smart part inherit some further base class to provide a deeper level of functionality.

I will continue happily work in both environments and really focus on getting the work done for the customer.

The Cobblers Shoes

The other day I was pointing out my Corporate web site to a person I was having a conversation with. When looking at this site I was completely embarrassed being a developer and focusing on quality. This site I whipped together on a Sunday afternoon to give my company a presence. This was done more then a year ago and I have been vowing to update the site and do it ‘Right’. The time is coming up to put in the time and effort to get it up to date using the corporate branding and technologies that we use here day to day. I have decided to go down the path of MVC for the core page handling technology for the update and hope to create a more interactive site that will contain more ‘good’ bits including downloads and development papers. This of course will take some time as I must continue to focus on client engagements, but I would definitely like to get a first pass up before Insights in Nashville, April 10th. The state of the website reminds me of the quote of the Cobblers shoes, where the worst shoes belongs to the cobbler who has the talent and capability to fix his own shoes. I hope through the next few months that I will feel more proud of the web site then I do now.


Successful Developer

Rich Eaton who works for Sage in the PSG group has started blogging. You can find his blog here. Rich’s most recent post is about what it would take to be a successful web developer and he will be providing some insight at ‘Insights’ on the attributes of running a successful web dev based consultancy. Rich and I have talks from time to time and he is a really nice guy with some good insight into things. Its worth adding him to your blog list.

With regards to his latest post, its easy to understand the tangibles. The checklist of capabilities one must have.. CSharp .. Check, … Check, JavaScript … Check …however I believe there are additional traits you need to ensure that you are successful.

The capability to Gut, Prune and Discover

Lightly put much of what we do now is ‘Groking’ new tech. This will change over time as the platforms change but the pure nature is to dig deep into the guts of things and understand how to accomplish the given task. Those who are truly long term will have a desire to get in a break things apart to see how they work. As you can imagine this information is invaluable for delivering end solutions build on the web platform

A Community Spirit

There is small number of Developers that are working on the Web Platform and of them a portion know it really well. As Rich mentioned there are places to obtain information such as Sage Training, Slx Developer, and Google. I really believe to build up the developer community for the web platform we will need to be even more community focused. I believe in the Past there may have been a fairly insular approach to knowledge sharing. I hope that is a thing of the past though I do believe that there are still those partners that take without contribution.

Energy, and flexibility

Honestly taking on the web platform can take some real investment in time and effort. This is not the old way of doing things. There are new practices, procedures and Technologies that will take time. There can be days as a developer that you will walk away and think I Just do not get it, but with time it will start to piece together nicely. In regards to flexibility, I think it is easy to fall into the trap of trying to code something in the way we did it in the past. Such as data access in the Lan vs. NHibernate in the web. We have to be open to the new ways, but and I say this with a big BUT we also have to be able to make decisions on the right tech for the implementation at hand.

Do not be afraid to Ask, but …

This is a journey that all of us must take if we want to develop for the web. Its ok to ask for help in the various forums. If someone is nice enough to help, say thank you, and maybe even make a comment on their blog, or on the forum. Also understand that (I suspect) that most help will come in the form of direction/details on how to resolve the issue yourself. Do not expect full coded examples as very few have time to come up with working code (unless they already have one)

I tend to read a lot, usually when I am done working for the day and I head to watch some TV. I generally have a book in my hand. I think the single biggest trait of a successful developer is the desire to learn.

Customer Portal

I am Working on a Customer Portal project and I was seeing some strange behavior. When ever I opened up a Lookup control a JavaScript  error was thrown and the resulting data was not being displayed. However after CTRL+F5 on the page the values would then show up. After discussing the problem and looking at the issues inside of Firebug to see that there was no named query available for the results to be generated. I was then pointed to the right place where the customer portal service list did not contain 2 very important entries.

So in a nutshell, ensure that in the customer portal the following 2 services are registered:


Service: Sage.Platform.NamedQueries.DictionaryBasedNamedQueryCacheService, Sage.Platform

Registered As: Sage.Platform.NamedQueries.INamedQueryCacheService, Sage.Platform


Service: Sage.Platform.NamedQueries.DictionaryBasedNamedQueryCacheService, Sage.Platform

Registered As: Sage.Platform.NamedQueries.INamedQueryLookupService, Sage.Platform


Once the entries were added all of the lookups in customer portal worked as expected.


The Sprit, my Thoughts

Loved the movie Sin City, so I thought I would watch the Spirit yesterday night. I really thought that this movie was  a waist of valuable time. Really stupid dialog, really stupid story and it looked as if it was trying to rely on the effects that for me were flat.

On a another note, while developing some smart parts in SalesLogix web there comes a time that the part has to become custom. That is the level of functionality exceeds the capability of the designers and/or the it serves better to work on the control in visual studio (my favorite environment). When the part is generated inside of AA an interface is created that represents the UI. When you convert it to a smart part you are effectively taking it out of the generation process and this interface will never be created. So when the site is deployed, if you do not clean the reference code in your smart part you will get a compile error when the page is accessed.

I also have gotten into the pattern of splitting out the code from the ascx file so that I can work on them as separate items. So when I convert a smartpart to custom (assuming I create it in AA first) I do the following steps.

1. Deploy and load the site into VS

2. Split the smart part to the Markup and Code files (add a new file with the same name smartpart.ascx.cs)

When this happens VS will ask me if I would like to put the code in the App_Code folder. Say no so that the file stays with the markup file.

3. Cleanup the markup (its not pretty in there).

I take a moment to cleanup and property indent the markup. This makes it easier for editing at a later date.

4. Make the coding changes required

I will make the changes required, including any refactoring required to simplify the smart part. I will also determine usage of the functionality inside and decide if some of the code should be promoted to common library

5. Test

Since I am in VS, I do both a build to determine any compile time errors and a run through the the functionality. This ensures that before I add it back to the support files for the portal its working as expect

6. Add as a support file(s)

I always work off a filebased VFS which has an extra benefit. I can basically just copy the changed files into the model in the appropriate directory location. This saves me from going to AA and doing the Add Folder … Add File steps which can take quite a long time.

Make sure to add the markup file (ascx), the code file and if available the App_LocalResource file as well.

7. Remove the smart part from the entity model

Once the support files  have been added, I go to the entity model and locate the smart part that I started with and delete it. This ensures that it does not get deployed instead of my new updated custom smart part.

That’s it for now. Hope the steps help someone.


Spring Cleaning

When you work at a home office it is easy to fall into a rut, where daily activities that just suck up time and energy and give nothing back intrude on quality of life. I am doing a personal audit of late and have noticed for me at least, a disturbing reality that my online life has overtaken my offline world. With Blackberry in hand, Email, IM, Twitter, Facebook and LInkedin  the number of disconnected interactions has only grown over the last year.

I totally get the stay connected thing but looking at the results of the being connected through these sites, I cannot see a distinctive benefit that has arisen. Whats worse for me is reflecting back and seeing that the amount of personal growth and family time has actually gotten smaller, and the times when I am away from the computer(s) I have found it difficult, feeling that I needed to be working or connected, as I might be needed or missing something important. There are things that are truly important such as this Blog, and my work email, however I am starting to understand that Facebook and Twitter have become for me at least a destroyer of what little extra time I have. Twitter, is like being a fly on the wall, listening into someone’s conversation and if you are lucky being able to inject yourself in and get a response. Facebook, while it is nice to be connected with old friends, family, co-workers and the like in a central place, the amount of visual ‘shit’ is overwhelming. Honestly each day that I log in I see changes, I get bombarded with play this, do that, take this survey, check out your IQ … Its this kind of white noise, over the top crap that just sucks the life out of me. Facebook has become a central aggregator or everything that is bad on the net. For the good parts of the site (stay connected) there (for me) is a lot of bad. I can understand the reasoning that the fine people at Facebook are throwing the stuff at the audience since they are still determining a business model, but Yuck! Some days it feels like a boot to the head.

So for me, Twitter is gone, not going to waist anymore time on it. I rather take the time that was committed to it and read, or get off my Ass and go for a walk. I say good bye to the constant notification that someone, somewhere posted something up. I say good bye to the need to verify that indeed what was posted had no meaning to me and I say good bye to the morning ritual of trying to catch-up to hundreds of non-contextual messages.

I spoke with a friend last week, and she had noted my status’s  in Facebook had/are pretty dull (I am here, or there, gonna watch a movie, or out with the family having desert). I reflected on that and looked over the status’s of my friends and noticed that they were in line. What I noticed more, what what has become news worthy which are the mundane actions, and lifestyles that many of us lead. If you dig, and not too deep forsure what we do from day to day is little more then getting up and putting in time. Its a sad state of affairs where the highlight is going out for a coffee, or a piece of cake is the highlight of ones days. Given the fact that I rarely have anything exciting to post I have decided to not post, to also reduce my ‘Facebook’ time to 15 minutes per week for managing my relationships.

I am hoping to further reduce my ‘computer social time’ to get out of this rut I have been in, spending more time with the computers then real people.

Do you find your time being negatively effected by these technological ways of staying connected.


Dell for a week

I have had my new notebook for a week now and I have to say I am quite happy with it so far. Except for the OS issue (that was quickly resolved) its quite pleasing to work with. Having a notebook with 8gb of memory does make a world of difference on the amount of work that can be managed. An considering I am a developer that has multiple copies of VS, Application Architect, and SQL enterprise manager open its good to still have snappy performance. We will see how it goes from here but not being tethered to a desk to have a good developer experience is a definite win in my books. I have also been getting into JQuery over the last week or so and really like what I see when it comes to the ease of the framework. I think every SalesLogix web developer should have some good strong knowledge of this library.

Vista version matters

I ordered a new notebook from Dell that arrived yesterday. After getting it setup and I started to do some development work and realized that I needed Digest Authentication on the IIS server. Well it seems that with Home Premium the authentication options are not available. I decided to head over to the local office depot and get the upgrade version of Vista and so far its taken more then 2 1/2 hours  (and still going) to upgrade the OS. Remember to have the right version of Vista depending on the development you are trying to do.

IDataService and Utility Methods

This morning I got into a IM discussion with Alexander Pfingstl. He works for for a BP in Germany. We were discussing the ability to handle custom address entry from the Add Contact Account screen in SalesLogix web. Since the format of German address layout is different then that of North America custom work needed to be done. Given that the current incarnation of the address control does not allow for customization it was not possible to make the changes there. Also using the Add/Edit address dialog was not possible because it works off an existing entity (account/contact) and not one that has yet to be created.

I had suggested that he just place the address details directly on the Add Contact screen and bind it directly. I have done this before and it works like a charm.

The next question that came up was how to call a business rule with out an entity. It seems that he has code that does a City lookup based on ZIP/Postal information. I am sure that we all have some form of this code around. What struck with me is that this code is not specifically entity bound and is more a utility method then a business rule. Really when you look at it from a consultant role this code should be as generalist as possible for maximum reuse.

As with most things I do, I recommended to create an external library in Visual Studio. I know, outside if AA where you may be saying that we should try to keep inside of the SalesLogix dev environment. This is were I would disagree. The goal is to create value for both the current customer, and others in the future.

In our discussions we talked about the DataService. With this service it is possible to get the underlying connection string to the SalesLogix database. You can also get a connection but I shy away from that as I like to know when it is created and destroyed so using the connection string gives me this flexibility.

So finally I opened up VS and a web portal and started to chunk out a code sample for Alexander and provided this code:

   1: public string GetCityFromZip(string zip)

   2: {

   3:     string result = string.Empty;

   4:     IDataService service = ApplicationContext.Current.Services.Get<IDataService>();

   5:     using (var connection = new OleDbConnection   (service.GetConnectionString()))

   6:     {   

   7:         connection.Open();   

   8:         using (var command = connection.CreateCommand())

   9:         {         

  10:             command.CommandText = "Select City from CityZipTable where Zip = ? "; 

  11:             command.Parameters.Add(new OleDbParameter("@Zip", zip));           

  12:             result = (string)command.ExecuteScalar();      

  13:         }           

  14:     }    

  15:     return result; 

  16: }

Now this code is specific to SalesLogix web as it uses the data service. To truly make it universal what should be done is a simple refactor to pass in the connection string instead of deriving it from the Data Service.

   1: public string GetCityFromZip(string connectionString, string zip)

   2: {   

   3:     string result = string.Empty;    

   4:     using (var connection = new OleDbConnection(connectionString))   

   5:     {      

   6:         connection.Open();       

   7:         using (var command = connection.CreateCommand())      

   8:         {         

   9:             command.CommandText = "Select City from CityZipTable where Zip = ? ";

  10:             command.Parameters.Add(new OleDbParameter("@Zip", zip));

  11:             result = (string)command.ExecuteScalar();      

  12:         }   

  13:     }   


  15:     return result;

  16: }


So now this method can be use from SalesLogix or an external application. Note the use of parameterized query to ensure that we do not get a SQL injection issue. So to call it from a SalesLogix web you can just create the following code:

   1: public void OnZipChanged(object sender, EventArgs args)

   2: {   

   3:     AddressUtilities utilities = new AddressUtilities(); 

   4:     string connectionString = ((IDataService)ApplicationContext.Current.Services.Get<IDataService>).GetConnectionString();    

   5:     txtCity.Text = utilities.GetCityFromZip(connectionString, txtZipPostal.Text);

   6: }

And using it from an external application its as simple as:

   1: public void UpdateCityBasedOnZip(string zip)

   2: {   

   3:     string connectionString = "<connection string here>";   

   4:     AddressUtilities utilities = new AddressUtilities();   

   5:     txtCity.Text = utilities.GetCityFromZip(connectionString, zip);

   6: }

So there you go, a library approach.

Hope this helps.