Monday, April 21, 2008

I'm still cleaning up code. One of the things that has never worked in NetTiers is the Microsoft Enterprise Library Exception Handling. I would get an exception thrown in the NetTiers code and the line was an exception with no data. I would get the error on a SQL insert via the NetTiers layers but no information about what was wrong with the data. Since I'm using the Insert where the param is the base type such as

   userService.Insert(newUser);

I knew that datatyping from a C#/.Net perspective wasn't the problem. I knew it was at a SQL level but I didn't know what it could be. So I finally had to fix the .NetTiers ExceptionHandling. I'm not sure why doesn't work right off the bat like the rest of NetTiers but I also didn't care enough to investigate. Once I get the ExceptionHandling working, I don't ever touch so I haven't had to REALLY understand it.

But now it has to work, it's hard to move forward without inserting data on this particular table. I knew I didn't have anything in web.config for this so that's where I started. I opened the ExceptionHandling Basic Quickstart and looked at the app.config. There were two different sections I added and then the true SQL error was displayed. While this isn't the entire work I'll have to do with Exception Handling on my pet project, at least I can keep going.

The SQL problem turned out to be that a datetime value was not being passed for a column where NULL was not allowed. Once the error handling showed the problem of datetime out of range, and I looked at the column definitions, I realized the problem.

Here are the sections I added to web.config:

1) in the <configSections>

<section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" />

2) the last entry before the end <Configuration> tag:

<exceptionHandling>

<exceptionPolicies>

<add name="Global Policy">

<exceptionTypes>

<add name="Exception" type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="None">

<exceptionHandlers>

<!--<add name="Wrap Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WrapHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" exceptionMessage="Global Message." wrapExceptionType="ExceptionHandlingQuickStart.BusinessLayer.BusinessLayerException, ExceptionHandlingQuickStart.BusinessLayer" />-->

<add name="Custom Handler" type="ExceptionHandlingQuickStart.AppMessageExceptionHandler, ExceptionHandlingBasicQuickStart"/>

</exceptionHandlers>

</add>

</exceptionTypes>

</add>

<add name="Handle and Resume Policy">

<exceptionTypes>

<add name="Exception" type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="None">

<exceptionHandlers />

</add>

</exceptionTypes>

</add>

<add name="Propagate Policy">

<exceptionTypes>

<add name="Exception" type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="NotifyRethrow">

<exceptionHandlers />

</add>

</exceptionTypes>

</add>

<add name="Replace Policy">

<exceptionTypes>

<add name="SecurityException" type="System.Security.SecurityException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException">

<exceptionHandlers>

<add name="Replace Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" exceptionMessage="Replaced Exception: User is not authorized to peform the requested action." replaceExceptionType="System.ApplicationException, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

</exceptionHandlers>

</add>

</exceptionTypes>

</add>

<add name="Wrap Policy">

<exceptionTypes>

<add name="DBConcurrencyException" type="System.Data.DBConcurrencyException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException">

<exceptionHandlers>

<add name="Wrap Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WrapHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" exceptionMessage="Wrapped Exception: A recoverable error occurred while attempting to access the database." wrapExceptionType="ExceptionHandlingQuickStart.BusinessLayer.BusinessLayerException, ExceptionHandlingQuickStart.BusinessLayer" />

</exceptionHandlers>

</add>

</exceptionTypes>

</add>

</exceptionPolicies>

</exceptionHandling>

 

 

Monday, April 21, 2008 7:10:16 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Saturday, April 12, 2008

My site has two roles: Admin, SecureUser, and three types of content:Admin, SecureUser, Public. I found that the code in the last post from Jeff Prosise wasn't managing roles in the SiteMap. For a visitor to the site that has not logged on (anon), the site map improperly showed Admin and Public pages. I checked the web.config and the SQL statement so it had to be either the database caching or the sql provider for sitemaps.

I google'd and found several posts in 2006 about this but none since so I knew it had to have been resolved. I found this blog post by Ishai Hachlili that had the code to deal with roles correctly. I added the code and the problem went away.

I'm not sure the code is robust enough to handle a large site but it fixed the problem for now.

As an aside, several of the 2006 posts said to just fix the web.config by making sure the <location> tags were correct. This meant any user could see links for the site that were restricted but would be denied access once they actually clicked on the page.  The location tags are only one solution to the problem. You need to have the sitemap, roles and the <location> tag to solve the problem. I go one step further and have the master page (1 for each area of the site) check the user and deny access.

 

Saturday, April 12, 2008 1:04:33 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, April 07, 2008

I stared working on my sitemap tonight. Never done the SiteMap stuff before. Opened my Pro ASP.NET 2.0 in C# 2005 that I use as a jump off point for intro topics I haven't touched yet. The chapter is great but I like my data in the database which gets backed up every night. I understood enough and even got a test page up using nested site map files. Hurray!

Now on to the SQL provider. I knew there had to be one so I googled and found an article with code by Jeff Prosise. The article covers the .cs file that is the SQL provider, as well as the web.config changes, the T-SQL, and the aspnet_regsql commands.

After you get the provider up and working, don't expect the SQL provider to show up in the Data Source Configuration Wizard:

You'll have the change the SiteMapDataSource to specify the Provider that you added to the web.config for SQL:

<asp:SiteMapDataSource ID="TotalSiteMap" runat="server" SiteMapProvider="AspNetSqlSiteMapProvider" />

 

But now my data is in the database and I changed the proc to be NetTiers-compliant so I can use their Admin pages for my data management.

Monday, April 07, 2008 8:22:52 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, April 03, 2008

The days when I don't have to deal with web.config are great. The days I have to go in there are bad, bad, bad. Why can't web.config be easy? Why can't it tell me more, and complain less. Why can't it be easily organized in some sort of logical pattern instead of loosey goosey? The registry looks great compared to web.config.

Is this fixed in the latest VS or .Net?

 

Thursday, April 03, 2008 8:38:24 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  | 
 Monday, March 31, 2008

And finally Wayne's Codesmith version for all procs prefaced with 'aspnet_':

<%@ CodeTemplate Language="C#" TargetLanguage="C#"  %>
<%@ Property Name="SourceDatabase" Type="SchemaExplorer.DatabaseSchema" %>
<%@ Assembly Name="SchemaExplorer" %>
<%@ Assembly Name="System.Data" %>
<%@ Assembly Name="System.Design" %>
<%@ Import Namespace="SchemaExplorer" %>
<%@ Import Namespace="System.Data" %>
USE [<%=SourceDatabase.Name%>]

GO

<%

foreach(CommandSchema command in SourceDatabase.Commands)
{
 %>
 
 <%
 if ((command.Name.Length>7) && (command.Name.Substring(0,7) == "aspnet_"))
 {
%>
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[<%=command.Name%>]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[<%=command.Name%>]

GO

<%
 }
}
%>

ASP.NET | CodeSmith | Dina | T-SQL
Monday, March 31, 2008 7:09:06 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 28, 2008

After using NetTiers for a couple of weeks now, here are some suggestions for usage:

1) Use NetTiers like any third party library. Build it and include the libraries. Do not alter code inside generated libraries unless mission critical. I also use the Microsoft.Patterns library. They ship the code but I don't alter it, I just use the built libraries. 

2) Prefix the library namespace with NetTiers so that the generated libraries look like NetTiers.Entities, NetTiers.Data, etc.

3) If you use NetTiers to generate your CRUD, set the ProcedurePrefix value to NetTiers_. When you are looking through a million procs, it easier to pass a whole section based on alphabetical sorting. If you use AspNet Membership, you will be accustomed to this naming schema as those procs are prefixed with aspnet_

4) If you create your own procs, prefix those procs to something that you won't confuse with any other library's procs, such as 'cust' for custom. Of cource, IncludeCustoms is set to true and CustomProcedureStartsWith should be set to 'cust_{0}_' so that a table name of Profile should have a custom proc of cust_Profile_SelectAll.

5) While still getting your template settings figured out:

  • Don't set ExecuteSQL to true until you have tested your generated SQL and looked through what was created.
  • Set LaunchVisualStudio to true and save yourself a few clicks.
  • Set ViewReport to false. You don't need another browser to open while you are still figuring out your templates.

6) Build the Web Service and the Admin site. Even if you don't plan to use AJAX or you have your own admin pages already built, these are just more examples of NetTiers code usage. Then when you need a data backdoor or quick AJAX, you are that much closer.

7) NetTiers documentation suggests using DeepLoad to get to a related table via FK. I can see how this would be used in their example of list of Orders in a grid and you also want to display the Customer's Name in the grid. What if you had a table of ProfileItems and a table of UserProfileItems and you wanted a list of all the ProfileItems in a grid with this user's settings? With the NetTiers usual get based on FK from either table, you won't get the grid I want (right?). So in that case, I'll create a custom proc with the proper bind.

Friday, March 28, 2008 8:03:23 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Thursday, March 27, 2008

I have a table with two FKs. NetTiers creates a stored proc for the PK as well as a stored proc for each FK however it doesn't create a stored proc that uses both FKs as the IN params. So I need to create this in a way that NetTiers can discover it and build the code objects to support it.

First I have to create the stored proc with a discoverable name. This requires several settings in the NetTiers template. First, that I want custom stored procs discovered so IncludeCustoms=true. Second, I want any stored procs to have a naming prefix so ProcedurePrefix=usp. Third, I need to handle the actual name of the stored proc. NetTiers uses discovery based on a template where the zeroth parm is the table name and the first parm is the Procedure Prefix so CustomProcedureStartsWith={1}_cust_{0}_. The remainder of the stored proc name is irrelevant but what is returned is very important. I usually return all columns which is NetTiers default object handling. If I choose not to include all columns, I would have to deal with an IDataReader or a DataSet.

If all the other stored procs and NetTiers code has been generated and you only new a few stored procs to be discovered, make sure to set ExecuteSQL=false and SourceTables=(only immediate tables.)

Once you generate your objects, you can verify the stored proc was discovered by looking in the Data layer in the base directory for the TableNameProviderBase.generatedCore.cs in the Custom Methods region.

Thursday, March 27, 2008 9:00:03 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Wednesday, March 26, 2008

I've been stuck in build hell for a week but now back to code. I want data that would normally be a JOIN between two tables. It's a join between ProfileProperties and UserProfileValues. But since I'm using NetTiers for my middle tier and I just want to get going, I'm writing a subpar GridView. The first column is pulled from a select of all profile properties provided by my ProfileDataSourceObject given to me by NetTiers. The second column is a function with a param of the profile property. The function grabs the user from the context and the profile property from the param, then determines what (if any) value has been set. This is not how I should do things. And since I usually don't do it this way, I'm sort of having to relearn some aspx syntax on how to do this.

I much prefer to have SQL return this data and just format it in the GridView. SQL doesn't change everytime Microsoft releases a new version of Visual Studio.

How would you do this?

 

Wednesday, March 26, 2008 7:30:31 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Tuesday, March 25, 2008

Building Separately

Building the NetTiers projects are getting tedious inside my main web app solution. I'm now building them separately and just moving into my main solution as references to each project. While I'm making so many database design changes, that is the best option. When the table designs and relationships are in place, I may move the .NetTiers projects back into my main solution.

Table Standards

One of my tables had the 'name' column as the last column as opposed to the column immediately following all the id,pk,fk columns. NetTiers decided only the next column after the id,pk,fk must be the most meaningful. It used this column which was not the name column but some non-determining column as the value for drop down lists in it's web admin site. So for everytable who had this table as a fk, this non-determining column populated as drop down list. So I had to change that in the database then regenerate the NetTiers projects.

NetTiers Admin site not converting to web app

This seems to be a common problem. One googled answer said to rebuild the project twice in a row and the conversion would succeed. I don't know what I did but when I selected the Admin folder and choose convert, I got a bogus error. Then I converted each file individually, and it succeeded.

NetTiers Admin Quick Look

The NetTiers CodeSmith templates create an admin site  (if you configure it to). Here is what a couple of the pages look like:


Tuesday, March 25, 2008 7:30:18 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Sunday, March 23, 2008

I finally got NetTiers up and running and wanted to see my data. I choose the last data table I designed. I just spent an hour trying to use NetTiers to see my data with their version of a DataSource for that table. I finally figured out the table has nothing to see. Ugh!!!

 

The last hiccups were web.config issues. Easily found answer on google.

 

So NetTiers templates are configured. NetTiers projects are integrated into my solution with several other projects. Everything builds. I can call the highest level web and data NetTiers objects. Now time to check in to source control. I'm checking in entire NetTiers template tree, all generated files from the templates, and all changes to my web app so that I can use NetTiers.

I don't build directly into my project tree so I have to copy the generated files over. This is a failsafe for now that I expect to eventually remove.

I already have a change to a table to make so I'll figure out how I want that process to go.

 

Sunday, March 23, 2008 7:29:15 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, March 21, 2008

I've been working for two hours to get my existing NetTiers CodeSmith Template to generate the files the way I need them. The NetTiers template gets 90% there out of the box but the template tips for each line item are sometimes obsure or require another lineitem to be TRUE. Then there is a fair bit of user error such as what to name the libraries created by the template, the directory they should be sent to. One error right out of the box is the LibraryPath value. It's inconviently stuffed in the Advanced CRUD section and just says Reference. After the projects try to build but fail but to the reference libraries not found, I figured out what was going on.

NetTiers generates the web service and client pieces which I keep in the template but don't use.

No I'm working on making sure my project library which includes all the libraries built by NetTiers CodeSmith has the right hierarchy in terms of having functions where I would expect them to be.

I'm sure at some point I'll actually get to the point where I call some of these great new classes.

Friday, March 21, 2008 8:26:32 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Monday, February 18, 2008

I'm getting farther along in my new pet project. I had many issues with converting to a web application project. Then I balked at which style of data access/data layer to use. Then I fidgetted with notation and styles. After wasting bunches of time, I'm finally moving along. Data is going in, data is going out. It looks aweful and the backend is a SQL client. But the user functionality is moving along. The rest can be fixed after I feel some momentum.

So I'm using asp.net 2.0 c# with sql backend. Enterprise Framework from MS patterns and practices. MS Membership provider with a SQL provider. Data layer is business objects with provider model. I have nunit plugged in but haven't written in unit tests yet. Argh!

Since I'm not a graphic designer, it looks BAD. A bad ripoff of www.xcache.com.

 

Programming to www.pandora.com.

 

ASP.NET | C# | Dina
Monday, February 18, 2008 10:53:19 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
 Friday, February 15, 2008

http://www.15seconds.com/issue/080214.htm - Create a Slide Show Using the AJAX SlideShow and TreeView Controls

ASP.NET | C# | Dina
Friday, February 15, 2008 7:45:19 PM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 

For the longest time I couldn't skin my custom control, background: a custom control looks like this:

public class MyGridView : GridView
{
...
}

This custom controls was in a separate class library.  Bill researched the problem and it appears that you can't skin a custom control that is in a nested namespace.  I.e. the custom control can't have this:

namespace MyNamespace.SubNameSpace
{
   public class MyGridView : GridView
   {   
   ...
   }
}

It has to be in a single namespace to work:

namespace MyNamespace
{
   public class MyGridView : GridView
   {  
   ...
   }
}

Visual Studio 2005 - .NET 2.0 - ASP.NET 2.0
{6230289B-5BEE-409e-932A-2F01FA407A92}

 

ASP.NET | C# | Wayne
Friday, February 15, 2008 9:16:58 AM (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [1]  |