Create Business Logic Layer and Data Access Layer for Web Service using Web Service Software Factory

Create Business Logic Layer and Data Access Layer for Web Service using Web Service Software Factory

by  David Hayden ( Florida .NET Developer )

 

I talked about using the Data Access Guidance Package in the Web Service Software Factory to generate stored procedures, business entities, and repositories to create a data access layer for a bare-bones blog engine. All of this code generation is handled by a few wizards as mentioned in the following post:

These guidance packages show the strength of the Guidance Automation Toolkit and Guidance Automation Extensions created by the Microsoft Patterns and Practices Group.

Going back to this database diagram of the blog engine which is the basis for all the code generation:

 

Code Generation from Database

 

I have successfully completed a simple end-to-end web service and bare bones winform client using the Web Service Software Factory that retrieves a blog post by postId from the database. Here you see the postId = 1, which was returned from the web service with the following post title and description. Below that are the 2 categories for which this post was assigned: “Pure NonSense“ and “Testing“.

 

Web Service Winform Client

 

I realize this won't win any awards, but it is step 1 in better understanding the guidance for creating web services using the Web Service Software Factory put out by the Microsoft Patterns and Practices Group.

 

Creating the Data Access Layer

The Data Access Guidance Package in the Web Service Software Factory does a lot of the plumbing to create / generate the Data Access Layer. However, I customized things a bit, because when I retrieve a post by postId, I want not only to get the post entity, but also the categories to which it is assigned in one database round trip. In a nutshell, I am returning two resultsets instead of one, and the factories created by the Data Access Guidance Package don't give you the option of doing this. You need to do this manually.

I haven't done any fine tuning or code-cleanup on this repository, so for now it looks like below:

 

public class PostRepository : Repository<Post>
{

private string databaseName;

public PostRepository(string databaseName)
    : base(databaseName)
{
    this.databaseName = databaseName;
}

public Post GetPostByPostId(Int32 postId)
{
    ISelectionFactory<Int32> selectionFactory =
        new GetPostsByPostIdSelectionFactory();
    Post post = new Post();
    
    try
    {
        Database db = DatabaseFactory.
              CreateDatabase(databaseName);

        using (DbCommand command =
          selectionFactory.ConstructSelectCommand(db, postId))
        {
            using (IDataReader rdr = db.ExecuteReader(command))
            {
                if (rdr != null) {
                
                // Resultset #1
                // Get Post Data
                GetPostsByPostIdFactory postFactory =
                           new GetPostsByPostIdFactory();
                while (rdr.Read())
                    post = postFactory.Construct(rdr);

                // Resultset #2
                // Get Post Categories Data
                GetCategoriesByPostIdFactory categoryFactory =
                       new GetCategoriesByPostIdFactory();
                    
                List<Category> categoryList =
                              new List<Category>();
                
                rdr.NextResult();
                while (rdr.Read())
                    categoryList.Add
                         (categoryFactory.Construct(rdr));

                post.Categories = categoryList;
                
                }
            }
        }
    }
    catch (SqlException ex)
    {
        HandleSqlException(ex, selectionFactory);
    }

    return post;
}
    
}

 

The GetPostsByPostIdSelectionFactory() hides the details and creates the DbCommand that is eventually run to get the post and the categories it is assigned to. It calls the stored procedure, GetPostsByPostId, with the input parameter of postId.

 

public DbCommand 
   ConstructSelectCommand(Database db, System.Int32 postId)
{

    DbCommand command =
        db.GetStoredProcCommand("dbo.GetPostsByPostId");
    db.AddInParameter(command, "postId", DbType.Int32, postId);
    return command;
}

 

The code above should look familiar. It is the Data Access Application Block in Enterprise Library 2.0 - a topic I have beaten to death on this blog :)

The actual mapping of the data in the resultsets to the business entities are done in a couple of factory classes that were auto-generated by the Data Access Guidance Package. Nothing real special about these classes:

 

public class GetPostsByPostIdFactory :
                 IDomainObjectFactory<Post>
{
    public Post Construct(IDataReader reader)
    {
        Post post = new Post();

        int blogIdIndex = reader.GetOrdinal("BlogId");
        if (!reader.IsDBNull(blogIdIndex))
        {
            post.BlogId = reader.GetInt32(blogIdIndex);

        }

        int descriptionIndex =
            reader.GetOrdinal("Description");
        if (!reader.IsDBNull(descriptionIndex))
        {
            post.Description =
                reader.GetString(descriptionIndex);

        }

        int nameIndex = reader.GetOrdinal("Name");
        if (!reader.IsDBNull(nameIndex))
        {
            post.Name = reader.GetString(nameIndex);

        }

        int postIdIndex = reader.GetOrdinal("PostId");
        if (!reader.IsDBNull(postIdIndex))
        {
            post.PostId = reader.GetInt32(postIdIndex);

        }


        return post;
    }
}

 

public class GetCategoriesByPostIdFactory :
                 IDomainObjectFactory<Category>
{
    public Category Construct(IDataReader reader)
    {
        Category category = new Category();

        int blogIdIndex = reader.GetOrdinal("BlogId");
        if (!reader.IsDBNull(blogIdIndex))
        {
            category.BlogId = reader.GetInt32(blogIdIndex);

        }

        int categoryIdIndex =
                 reader.GetOrdinal("CategoryId");
        if (!reader.IsDBNull(categoryIdIndex))
        {
            category.CategoryId =
                    reader.GetInt32(categoryIdIndex);

        }

        int nameIndex = reader.GetOrdinal("Name");
        if (!reader.IsDBNull(nameIndex))
        {
            category.Name = reader.GetString(nameIndex);

        }

        return category;
    }        
}

 

Create the Business Logic

Once we have the data access layer completed, the business logic class for getting the post by postId is nothing more than calling the repository:

 

public class GetPostAction
{
    public Post Execute(int postId)
    {
        PostRepository postRepository =
          new PostRepository(DataAccessConstants.
                                      DatabaseName);
        return postRepository.GetPostByPostId(postId);
    }
}

 

Although I don't want to get into this yet, the domain logic above will be called by a class up in the service implementation layer as such:

 

public DataTypes.Post GetPost(int postId)
{
    TranslateBetweenPostAndPost translator =
              new TranslateBetweenPostAndPost();

    GetPostAction action = new GetPostAction();
    BusinessEntities.Post post = action.Execute(postId);

    return translator.TranslatePostToPost(post);
}

 

and there we have the data access layer details surrounding the Web Service Software Factory. This, of course, is all subject to change as they continue to evolve the role and output of the Data Access Guidance Package in the Web Service Software Factory.

 

Conclusion

Hopefully this sheds a little light on the Business Logic Layer and Data Access Layer of the Web Service Software Factory as it sits now. For further information, stay tune to my blog and check out the other resources:

 

Written By: David Hayden ( Florida .NET Developer )

Filed: Web Service Software Factory

 

posted on Tuesday, September 26, 2006 3:59 PM

Main

David Hayden Google +

David Hayden Twitter

Health & Fitness

JavaScript Patterns Book Review

HTML 5 and CSS3 - Develop with Tomorrow's Standards Today

Professional ASP.NET Design Patterns Book Review

Beginning Mac Programming Book Review

C# in Depth Book Review

ASP.NET MVC

Orchard CMS

Categories