Multi-blog Obsession

by Jacob 6. April 2009 05:26

TwoBlogsThe multi-blog data provider for BlogEngine.Net has been taking up a lot of my brain space lately—to the point that I’m able to announce that it is installed and working “in the wild” on a hosted site (though not in anything like a heavy-load situation). I now have a copy of both my dev site and my personal site up and running from the same directory (and the same database). Frankly, I didn’t think it’d be as easy as it was. This success prompted me to create a 2.0 release (that is now up on the CodePlex site).

Getting Static

My main fear was with the heavy use of static variables in BlogEngine.Net. You see, BE.Net loads all the data into memory using static List variables. I found this out when I went looking for the best way to store a BlogId (so that it didn’t have to parse against an Url every time a request came through).

While there are pros and cons to keeping your entire blog in memory (pro: speed and ease, con: memory bloat and a large delay on any request that triggers a data load), my concern was how an application would react when it had to serve two sets of data. Fortunately, it seems that even when two sites share an application pool on IIS, they still keep their static spaces separate. I’m not sure what I was going to do if it didn’t but I was spared the tragedy.

Configuration

Installing the blog provider mainly involves copying the binary into the /bin directory and then updating the web.config to point to the right driver. There are three providers in your web.config that are affected.

Blog Provider

The blog provider handles the blog data. Settings, posts, categories and suchlike. Add the provider and update the “defaultProvider” tag and you’re ready to go.

<BlogEngine>
  <blogProvider defaultProvider="SQLBlogProvider">
    <providers>
      <add name="SQLBlogProvider" type="BlogEngine.SQLServer.SqlBlogProvider, BlogEngine.SQLServer" connectionStringName="BE"/>
    </providers>
  </blogProvider>
</BlogEngine>

Membership Provider

The membership provider handles user authentication and management (stuff like changing passwords and such). Technically, you don’t need to change this, but if you don’t the users will be the same across blogs (not a problem if you aren’t multi-blogging). I frankly haven’t tested if a mixed-configuration actually works but it should. Again, add the provider and update the “defaultProvider” tag and you’re ready to go.

<membership defaultProvider="LinqMembershipProvider">
  <providers>
    <clear/>
    <add name="LinqMembershipProvider" type="BlogEngine.SQLServer.LinqMembershipProvider, BlogEngine.SQLServer" passwordFormat="Hashed" connectionStringName="BE"/>
  </providers>
</membership>

Role Provider

The role provider handles authorization and what users are assigned to which roles. Again, you don’t technically have to change this if you don’t need it. Also again, it’s simply a matter of adding the provider and changing the “defaultProvider” tag.

<roleManager defaultProvider="LinqRoleProvider" enabled="true" cacheRolesInCookie="true" cookieName=".BLOGENGINEROLES">
  <providers>
    <clear/>
    <add name="LinqRoleProvider" type="BlogEngine.SQLServer.LinqRoleProvider, BlogEngine.SQLServer" connectionStringName="BE"/>
  </providers>
</roleManager>

Multiple-blog Configuration

To set stuff up for multiple blogs, you’ll need to run a script or two in your database and add a tag to all the providers. There are two script files (included in both the binary and source files), one for setting up the initial database changes (DatabaseSchemaChanges.sql—mostly adds tables) and another for adding the base values for a new blog (AddNewBlog.sql).

I wanted to make this easier by having the driver do the updates for you. That may still happen in the future, but since BlogEngine.Net itself requires manually running a script if you want to use the database provider I decided not to sweat it too hard. Presumably, anyone running in a database has to be running scripts manually anyway so this isn’t going to be a show stopper.

The provider will run just fine after running either script, even if you aren’t using multiple blogs. In other words, just because the database changed doesn’t mean that the single-blog installation is hosed. The exception to this is the “be_Settings” table. If you’re going to run for a while with a single-blog after running the first script, you’ll want to add a default to the BlogId column so it doesn’t choke when you insert and update settings.DefaultBlogId

Both scripts are “templated” so you can change key factors (a table prefix on the first and a couple of blog values in the second). Filling in the template is a matter of hitting ctrl-shift-M in Query Analyzer or SQL Server Management Studio. That’ll bring up a prompt for what values you want those template variables to have.TemplatePrompt

The final thing to setup is to add a multiblog attribute on the providers. That’ll make your providers look something like this.

<add name="SQLBlogProvider" type="BlogEngine.SQLServer.SqlBlogProvider, BlogEngine.SQLServer" connectionStringName="BE" multiblog="true"/>

The provider selects the blog it wants to deliver based on three configured values.

  • Host is the base address. The provider matches the Host value against the end of the host (so rabidpaladin.com will match “rabidpaladin.com”, “www.rabidpaladin.com” and “blog.rabidpaladin.com”).
  • Path is the rest of the Url. The provider matches the Path value against the start of the requested path.
  • Port is the port (if any) in the Url. Honestly, I threw this one in there as much for my testing as for any real-world use I expect it to see.

Tags

One thing I added (at the provider level) is that when a post comes in without any tags, the provider takes a moment to scan for tags in the post body. This is a feature I did the initial work for in Subtext so porting it over was a matter of a couple minutes. Any time a post is inserted into the database, the provider checks if it has tags yet. If no tags are present, it will scan the content for appropriate anchor markup (like those produced for Technorati tags). That means that on import, my posts all had their tags correctly populated—saving me a lot of extra work (or face losing tags on imported posts). That I was able to avoid the brain-damaged tag handling of BlogEngine.Net is just a bonus (they lower-case tags on creation and then re-capitalize them when serving them up).

Other Stuff

As I said, this should get you set up. Since I used this blog provider from the start on both my blogs, I can verify that the import tool works just fine in a multi-blog configuration. As far as BlogEngine.Net is aware, it’s doing the same stuff it always has. Indeed, the only change I made from BlogEngine.Net’s standard v1.4.5 release was in UrlRewrite.cs to allow links produced by Subtext to still work (so I don’t throw errors on old links).

else if (url.Contains("/POST/") || url.Contains("/ARCHIVE/"))

I submitted a patch at one time to have this hit the base source code but apparently it wasn’t deemed worthy.

Also, I found that running the provider in IIS7 is a bit tricky. Since BlogEngine.Net loads extensions from the database on application start you’ll get errors if you are configured for “Integrated” mode. That’s because “Integrated” mode (quite properly) fires the application start event before the HttpContext.Request is populated (which is what I’m using to determine what blog is being requested). Setting the application pool to “Classic” mode will solve this “problem”.IIS7ClassicMode

Looking Forward

My blogs are still running Subtext at their base addresses. I’m still not quite ready to take the plunge on BlogEngine.Net.  I am, however, undoubtedly one step closer.

Tags: , , , , , , ,

Programming

Multiple Blog Data

by Jacob 29. March 2009 09:01

PartialSchema So I have a working LINQ to SQL provider for BlogEngine.Net. Now what? Given a little spare time, how about I see if I can’t use it to support running multiple blogs from the same installation? More importantly, see if I can use it to support running multiple blogs from the same database?

Doing just that turns out not to be all that difficult.

Scheming

The current architecture for BlogEngine.Net’s data already has a bit more cohesion than it technically needs. All the objects have their own individual Ids and those Ids are used to relate objects to each other (though there is one exception). Since every object already has its own Id (usually a Guid), splitting objects into separate blogs isn’t the chore it might otherwise have been.

There are two options when it comes to dividing items up into multiple blogs. First, each object can have a column added to its table to indicate which blog it is associated with. Second, you can create a cross-reference table that associates a blog Id with the object Id for the blog.

Columns
My initial impulse in most cases would be to add a BlogId column to the tables where it is needed. The reason is simple: objects belonging to the blog are in a true parent-child relationship and that relationship is generally best expressed as a field on the child indicating its parent. The relationship can (and really should) be enforced with a foreign key constraint on the column to ensure that the relationship is intact.

Cross-references
Having cross-reference tables is a bit more problematic and carries with it some maintenance and performance concerns. Not only does it force a join when you want to read the objects for a specific blog, but it means that insert, update, and delete commands now have to involve two tables instead of just one. One advantage of cross-reference tables is that they’re easier to extract back out if you need to devolve your data. Additionally, foreign key constraint integrity is triggered when the cross-reference entry is created instead of on your blog objects themselves—making your touch a bit lighter if you have other actors in the system.

Complicating Things 
No decision is best for every occasion, and when it came time to design how I wanted multiple blogs to work, I was really reluctant to mess with the native tables of BlogEngine.Net. I’m not sure if my hesitation is a matter of respect for a project I’m not involved in or if I’m just being unreasonably squeamish, but I eventually chose to go the cross-reference route. My main reasoning is that I wanted my intrusions to remain light and easily devolved.

I ♥ Linq

Now, normally, adding a super-structure on top of an existing infrastructure is a real pain. Editing all your SQL statements manually becomes an exercise in precision string manipulation and if you’re working through stored procedures… ugh. Linq made this really easy.

Here’s an example from the FillProfiles method of the blog provider.

var profileData = from p in context.Profiles
                  select p;
if (isMultiBlog)
{
    profileData = from p in profileData
                  join bp in context.BlogProfiles on p.ProfileID equals bp.ProfileId
                  where bp.BlogId == Utils.GetBlogId()
                  select p;
}

The initial select is good for the general case. It pulls all the objects from the Profiles table. Adding a filter when we have multiple blogs is added in the if clause. Note that the second select references the first (“from p in profileData”). Linq knows that the second “from” is a refinement of the first and puts them together logically. Since Linq defers execution of the query until it’s actually used, the query sent to the server includes the full constraint (i.e. filtering happens on the database). Here’s the statement that’s actually sent.

SELECT [t0].[ProfileID], [t0].[UserName], [t0].[SettingName], [t0].[SettingValue]
FROM [dbo].[be_Profiles] AS [t0]
INNER JOIN [dbo].[be_BlogProfiles] AS [t1] ON [t0].[ProfileID] = [t1].[ProfileId]
WHERE [t1].[BlogId] = @p0

This method ensures that you only take the hit of the join if you are in a multi-blog setup. And without pulling everything to the client.

Settings

I had some fun with the Settings table because it is an exception to BlogEngine.Net’s Id rigor. It has interesting impact on the Linq situation, but I think I’ll give it its own (short) post later.

Beta Available

So I tested this in my own home-grown environment and it seems to work as expected. In consequence, I’ve created a new release at the project homepage. I’m calling it a beta, though it barely warrants the label. I worry that it has only been tested in a single environment. If you’re a hearty soul and a BE.Net user, please give it a go. I’ll be spending some time getting it set up and tested in an actual public setting with my personal blogs here shortly. As always, I welcome feedback either at codeplex or comments or via email.

Tags: , , , , , , ,

Programming

Gratuitous Use of Linq

by Jacob 7. March 2009 06:10

PowerShovel Every now and then I get to doing something just because... well, because I can. These projects usually atrophy before becoming anything usable and serve more as a way to explore and practice than anything else. Usually. My latest tangent actually got to a state where I can let it loose in the wild and it'll probably actual do what it is supposed to do.

BlogEngine.Net

Let me be perfectly clear up front: I don't actually use BlogEngine.Net at all. Anywhere. I'm still a Subtext guy when it comes to blogging software. BlogEngine.Net still lacks critical features and that prevents me from using it as yet (primarily running multiple blogs from a single installation/database).

That said, BlogEngine.Net is a lovely little product with a lot to like about it. The extensibility model is extremely easy to use and flexible. The theming doesn't suck. And its architecture is easy to navigate/understand even while it makes investments in areas I consider likely to payoff.

Data Access

While I like the product, the data access bugs me more than a little. It uses a provider model and includes built-in XML and database providers. These are good things. For flexibility, the database provider uses System.Data.Common and the DbProviderFactory with string-built commands. This structure allows BlogEngine.Net to be able to use any database that has a .Net data provider (including things like MySQL, SQLite, or VistaDB). Incidentally, they downplay (unintentionally?) this feature on their website saying in their FAQ that they support XML and “the SQL Server provider”.

At any rate, here's their SelectPage implementation as an example

public override Page SelectPage(Guid id)
        {
            Page page = new Page();
 
            string connString = ConfigurationManager.ConnectionStrings[connStringName].ConnectionString;
            string providerName = ConfigurationManager.ConnectionStrings[connStringName].ProviderName;
            DbProviderFactory provider = DbProviderFactories.GetFactory(providerName);
 
            using (DbConnection conn = provider.CreateConnection())
            {
                conn.ConnectionString = connString;
 
                using (DbCommand cmd = conn.CreateCommand())
                {
                    string sqlQuery = "SELECT PageID, Title, Description, PageContent, DateCreated, " +
                                        "   DateModified, Keywords, IsPublished, IsFrontPage, Parent, ShowInList " +
                                        "FROM " + tablePrefix + "Pages " +
                                        "WHERE PageID = " + parmPrefix + "id";
 
                    cmd.CommandText = sqlQuery;
                    cmd.CommandType = CommandType.Text;
 
                    DbParameter dpID = provider.CreateParameter();
                    dpID.ParameterName = parmPrefix + "id";
                    dpID.Value = id.ToString();
                    cmd.Parameters.Add(dpID);
 
                    conn.Open();
                    using (DbDataReader rdr = cmd.ExecuteReader())
                    {
                        if (rdr.HasRows)
                        {
                            rdr.Read();
 
                            page.Id = rdr.GetGuid(0);
                            page.Title = rdr.GetString(1);
                            page.Content = rdr.GetString(3);
                            if (!rdr.IsDBNull(2))
                                page.Description = rdr.GetString(2);
                            if (!rdr.IsDBNull(4))
                                page.DateCreated = rdr.GetDateTime(4);
                            if (!rdr.IsDBNull(5))
                                page.DateModified = rdr.GetDateTime(5);
                            if (!rdr.IsDBNull(6))
                                page.Keywords = rdr.GetString(6);
                            if (!rdr.IsDBNull(7))
                                page.IsPublished = rdr.GetBoolean(7);
                            if (!rdr.IsDBNull(8))
                                page.IsFrontPage = rdr.GetBoolean(8);
                            if (!rdr.IsDBNull(9))
                                page.Parent = rdr.GetGuid(9);
                            if (!rdr.IsDBNull(10))
                                page.ShowInList = rdr.GetBoolean(10);
                        }
                    }
                }
            }
 
            return page;
        }

I want to reiterate that I'm not ripping on their choice to use this data access methodology. If you want the flexibility to use any .Net supported data provider without a third-party dependency, this how you get it. You could optimize some of the stringiness, but with trade-offs.

Linq, Linq, Baby

That said, I don't mind being tied to SQL Server and if I'm going to muck with the data layer (like, say, if I'm going to attempt multiple blogs from a single application instance) I want something simple that I can use without all that extra goo. I looked for any hint that this might have been done already, but I couldn't find anything. It looks like I'm the only one with this particular manifestation of brain damage, however.

Since configurable table prefixes are a desirable feature and since that's easier to do in Linq to SQL I figured it'd be best to go that route. It was good to get the table prefix stuff into a working project and have it work about as I expected it to.

Implementing the BlogEngine.Net blog provider turns out to be pretty easy in Linq. Ditto the Role and Membership providers. I tried to stay as close as possible to the DbBlogProvider. Even so, I found that some of the admin components are picky enough that even little things could bite me (the category editing page blows up if you leave category descriptions null, for example).

For compare and contrast, here's my SelectPage method using Linq to SQL

public override Page SelectPage(Guid id)
{
    Page page = null;
    using (Data.BlogDataContext context = getNewContext())
    {
        Data.Page pageData = (from p in context.Pages
                              where p.PageID == id
                              select p).FirstOrDefault();
        if (pageData != null)
        {
            page = new Page()
            {
                Id = pageData.PageID,
                Title = pageData.Title,
                Description = pageData.Description,
                Content = pageData.PageContent,
                Keywords = pageData.Keywords,
                DateCreated = pageData.DateCreated.HasValue ? pageData.DateCreated.Value : DateTime.MinValue,
                DateModified = pageData.DateModified.HasValue ? pageData.DateModified.Value : DateTime.MinValue,
                IsPublished = pageData.IsPublished.HasValue ? pageData.IsPublished.Value : false,
                IsFrontPage = pageData.IsFrontPage.HasValue ? pageData.IsFrontPage.Value : false,
                Parent = pageData.Parent.HasValue ? pageData.Parent.Value : Guid.Empty,
                ShowInList = pageData.ShowInList.HasValue ? pageData.ShowInList.Value : false
            };
        }
    }
    return page;
}

BlogEngine.Net for SQL Server

So I got the thing working and thought I'd open it for “the community”. Since BlogEngine.Net is on CodePlex, that was a natural choice. Anyone sharing my peculiar proclivity is invited to head on over, take a poke and let me know what can change for the better. Or better yet, submit a patch. Or better, better yet, join the project. (also: CodePlex's recent transparent svn compatibility is awesome! When did that happen?)

If you do poke at the project, some forewarning. First, I don't have unit tests for this and don't plan on any (I'm not against using them, I just don't want the headache of creating them myself). Data access is more in the realm of “integration testing”, so I'm not sure there's much you can really do that's actually useful. It might be different if BlogEngine.Net had a suite of tests I could use to validate my providers against, but...

Second, I haven't gone out of my way to do a lot of commenting. This is deliberate. These methods are short, should be self-explanatory, and since they should be hidden behind a provider I didn't even bother with the typical XDoc stuff. Anything directly accessing them such that intellisense comes to bear is doing something wrong...

Room to Improve

In the end, this is the ground-work to remove an (admittedly trivial) barrier in working with BlogEngine.Net. I hope to help move as much as possible into the database in order to support things like multi-blog configurations. BlogEngine.Net hasn't been very disciplined in its storage layer and XML really is the default medium. Things like referrer tracking don't use a provider at all so you really can't (yet) get away from XML files in your App_Data directory (and hence, read/write permission configuration). Since I want that to change, I'm going to see if I can't get that going a bit.

Things to do
  • Decide on a database update methodology (so far, I'm using the already-existing tables and hence piggy-backing on the BlogEngine.Net scripts)
  • Replace the built-in ReferrerModule (use/create provider model access for referrers?)
  • Comb the project for any other errant XML dependencies
  • Work on multi-blogging configuration

Tags: , , , , , ,

Programming

So You Think You're An Admin?

by Jacob 14. February 2009 22:56

Access Button I had an interesting problem crop up trying to run my own application this week. We have a routine that uses an excel spreadsheet to import orders into Dynamics GP that includes some twists that aren't handled well by Integration Manager. Since the application runs from the network (using ClickOnce) and because these orders can be substantial and represent a commitment of corporate resources, we want some control over who can run them. Specifically, we use Active Directory group membership with hard-coded/defined groups.

One of the groups I want to allow is Domain Admins. And yes, this is a kludge. All three members of our small IT shop are Domain Admins—mainly so that we can act as backup when the others are unavailable. It's a handy kludge, though, so lump it. Unfortunately, when running from my machine (running Vista), the user token being used to check Identity.IsInRole() wasn't admitting that I am, in fact, in the Domain Admins domain group

This is, by the way, the first I've run into an inversion of Works on My Machine™.
 works-on-my-machine-starburst-not

The Problem

It wasn't terribly difficult to figure out what was wrong. The key to the problem is that Vista UAC (which I actually rather like because I want to know when programs undertake certain activities) creates a “split token” when you login using an account with admin privileges. The user actually runs using the filtered token that removes the dangerous things and only elevates (with user notification and approval) when those privileges are actually needed.

So when I asked WindowsIdentity.IsInRole("COMPANY\Domain Admins") it told me that it's never heard of that role and certainly I'm not a member of it. This was disconcerting.

Now the problem goes away if you start Visual Studio with “Run as Administrator” or start an application with a shortcut with that setting. Which works fine (not great) while developing (if you remember to start VS as administrator) but eventually I got tired of it and sometimes I want to run the deployed app from my box. There's just one small hitch. Remember that I mentioned that we deploy the app to the network using ClickOnce? It turns out that there's no good way to start a ClickOnce app with elevated privileges. Googling around (and even checking Stack Overflow) I found some people who wrote what were essentially batch files or ran services that could then be used to elevate processes either to run ClickOnce apps or to allow ClickOnce apps to do stuff that requires elevation. But really, that's a lot of hassle for something I just knew had to be simpler.

The Solution

After beating my head on the problem for a bit, I eventually took a step back and asked myself that crucial dev question: “What am I actually trying to accomplish here?” I need to remind myself to do that sooner when I find myself “brought to Point Non Plus” (as Georgette Heyer's characters might say). It turns out to be a good question and one that led to the “Duh” moment I share with you now.

Since I'm not actually doing anything that requires admin privileges, going for process elevation is a complete waste of time. All I really want to know is if the current user is part of a specific Active Directory group. Didn't I see something about .Net Framework 3.5 and managed domain objects? Why yes! Yes I did!

The nifty little buggers are in System.DirectoryServices.AccountManagement and if you do anything with Active Directory domains you owe it to yourself to give this namespace a once over. Here's what I ended up with:

bool isAllowed = false;
WindowsIdentity wi = WindowsIdentity.GetCurrent();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "COMPANY"))
{
    UserPrincipal up = UserPrincipal.FindByIdentity(pc, wi.Name);
    GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "Domain Admins");
    if (up.IsMemberOf(gp))
        isAllowed = true;
}

This worked right out of the chute. Well, getting the right AD group membership didn't want to work when using the Principal.IsMemberOf(PrincipalContext, IdentityType, string) overload, but pulling down the actual GroupPrincipal looks cleaner anyway, I find.

Tags: , , , ,

Programming

Changing Table Names in an OR/M

by Jacob 27. August 2008 11:33

Empty Sign I spent some quality time googling this and even went and asked the nascent Stack Overflow community and didn't come up with a satisfactory answer. Being the intrepid sort, I opened up a test project and started poking around, compiling information from a number of sources and playing until I got something that worked. For your amusement and/or edification, I'll document what I found.

What I Want to Do

The basic scenario is that many typical “commodity” web applications use databases to store their information. Since most web hosting services come with a single database but charge extra for additional databases, it is common for web-type products to add identifier text to their table and stored procedure names*. The .Net blog software I sometimes contribute to, Subtext, is an example. Take the table I added to hold tags associated to posts a while back, “subtext_Tag”. Using the “subtext_” prefix means that we won't run into naming collisions on our tables if someone has a wiki or forum application that also contains a table for tag entities named “Tag”.

 

* And yes, as one user on Stack Overflow suggested, you could use schema as a differentiator so we could as easily have used a “subtext” schema and our tables would be “subtext.Tag” instead of “dbo.Tag”. That solution is much trickier to setup than a simple table naming convention, though, so I think I prefer the table prefix for now.

 

The .Net Way

While I was initial open to any .Net OR/M the fact of the matter is that the only one I know anything about is SubSonic. Now I like SubSonic a lot, but their tools are geared towards code generation and I couldn't find a handle into runtime manipulation of table names (such might exist, but I was unable to find it).

Since I'm even less familiar with the other third party .Net OR/M data tools (like LLBLGen or NHibernate) and nobody on Stack Overflow (who tend to be knowledgeable about these things) spoke up, I decided to check out what it would take to monkey with the table names at runtime using stuff I have actually used. Namely the Entity Framework and LINQ to SQL. It turns out to be possible in either, though I have to admit to being surprised that it is easier in LINQ to SQL than in EF.

My Test Database

To keep things simple, I created a test database. Since I am a highly creative professional, I named it “Test” and created a table there named “TestTable”.

Test Schema 

LINQ to SQL

Instantiating a new DataContext object in LINQ to SQL includes a constructor that allows you to feed in a MappingSource derivative. By default, L2S uses an attribute mapping object that pulls the metadata from attributes on your classes—in this case the “Name” property of a TableAttribute.

[Table(Name="dbo.TestTable")]
public partial class TestTable : INotifyPropertyChanging, INotifyPropertyChanged
 

Since attributes are immutable at runtime, using the default isn't an option here. Fortunately there's an XmlMappingSource object that can use an XML file (or fragment) to do what I need. Unfortunately, generating an initial mapping file is a touch cumbersome and requires use of the SQLMetal.exe tool provided with Visual Studio.

Here's how (after adding a TestLINQ.dbml file and dragging the table onto it—pre-name-change of course):

  1. I opened the VS Command Prompt (it's in a Visual Studio Tools folder in the start menu).
  2. Changed the directory to my project.
  3. Entered the command “sqlmetal /map:TestLINQ.map /code TestLINQ.dbml”. This generates a TestLINQ.map file.
  4. Right-clicked on the generated file in my project and selected “Include in Project”.
  5. Set the file's “Copy to Output Directory” property to “Copy Always”.

The mapping file is pretty simple. The relevant bit is the Name attribute of the Table element:

<Table Name="dbo.test_TestTable" Member="TestTables">
  <Type Name="LINQ.TestTable">
    <Column Name="TestId" Member="TestId" Storage="_TestId" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
    <Column Name="TestOne" Member="TestOne" Storage="_TestOne" DbType="VarChar(50)" />
    <Column Name="TestTwo" Member="TestTwo" Storage="_TestTwo" DbType="VarChar(50)" />
  </Type>
</Table>
 

Make sure the name is what you want it to be and you're golden. Here's the code I used to test it out after the name change.

XmlMappingSource source = XmlMappingSource.FromUrl("TestLINQ.map");
using (LINQ.TestLINQDataContext context = new LINQ.TestLINQDataContext(Properties.Settings.Default.TestConnectionString, source))
{
    LINQ.TestTable table = new LINQ.TestTable()
    {
        TestOne = "firstLINQ",
        TestTwo = "secondLINQ"
    };
    context.TestTables.InsertOnSubmit(table);
    context.SubmitChanges();
 
    table.TestOne = "thirdLINQ";
    context.SubmitChanges();
 
    context.TestTables.DeleteOnSubmit(table);
    context.SubmitChanges();
}
 

XmlMappingSource even has a .FromXml() method that will create your map from an Xml fragment string.

Entity Framework

As I mentioned before this one is harder. This is a surprise because EF is ostensibly created to make it easier to keep your object definitions separate from your storage definitions. The reason it isn't easier is understandable once you realize that EF is made to be highly configurable and thus its definition files are much more complex than the L2S mapping.

The first problem with EF, though, is that the documentation is schizophrenic. Also confusing. That's because MS rolled the original three configuration files into the .edmx definition file so references on the web imply that those files are easily seen and edited. Even more confusing is that EF actually still uses the .csdl, .ssdl, and .msl files at runtime—it just generates those files from the .edmx and either packs them in the assembly as a resource (by default) or as files in your output directory.

Well, to monkey with the tables at runtime, you have to have access to the configuration files. To do so you need to change the default in the “Metadata Artifact Processing” property of your ConceptualEntityModel and rebuild the project. That'll put perfectly good .csdl, .ssdl, and .msl files in your output bin directory (You don't have to leave it at "Copy to Output Directory" once you have saved these files off for your own use and abuse.)

EF did another funky thing by deviating from the norm in what it pulls from the connection string that you feed it. If you look at your EF connection string in app.config (or web.config) you'll see something like this:

<add name="TestEntities" 
connectionString="metadata=res://*/TestEF.csdl|res://*/TestEF.ssdl|res://*/TestEF.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=localhost;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
 

Notice that there's a “provider connection string” embedded in the connectionString attribute—that's the “normal” connection string that tells EF what database to use for storage. Also notice that the metadata property tells EF where to go for those configuration files (in this case, it's telling EF to look in the assembly for resources TestEF.csdl, TestEF.ssdl and Test.msl).

Armed with this information, I was able to add a set of generated config files to the project stolen from those generated in the output directory. Once there, you have to edit the storage file and the mapping file to use the altered names. The table name used by EF is taken from the Name attribute of the EntitySet element in the .ssdl file. This is unfortunate because the Name attribute is a reference used by things like associations. Which means that you have to make sure you alter all the references to that EntitySet as well (fortunately, these are generally referenced using an EntitySet attribute on the relevant association and thus are relatively easy to find).

<EntitySet Name="test_TestTable" EntityType="TestModel.Store.TestTable" store:Type="Tables" Schema="dbo" />
 

It's not necessary to alter the EntityType, though I found that if you alter it consistently across the file it will work if you do.

The mapping configuration in the .msl file just has to be updated so that the objects use the correct EntitySet for storage.

<EntitySetMapping Name="TestTable">
  <EntityTypeMapping TypeName="IsTypeOf(TestEF.TestTable)">
    <MappingFragment StoreEntitySet="test_TestTable">
      <ScalarProperty Name="TestId" ColumnName="TestId" />
      <ScalarProperty Name="TestOne" ColumnName="TestOne" />
      <ScalarProperty Name="TestTwo" ColumnName="TestTwo" />
    </MappingFragment>
  </EntityTypeMapping>
</EntitySetMapping>
 

Once those changes are made your code will work with the altered table name, though you need to alter the connection string to look for the correct configuration files. Here's the final code I used to test it out.

string connection = "metadata=TestEF.csdl|TestEF.ssdl|TestEF.msl;provider=System.Data.SqlClient;provider connection string=\"Data Source=localhost;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True\"";
using (TestEntities entities = new TestEntities(connection))
{
    TestTable table = new TestTable()
    {
        TestOne = "firstEF",
        TestTwo = "secondEF"
    };
    entities.AddToTestTable(table);
    entities.SaveChanges();
 
    table.TestOne = "thirdEF";
    entities.SaveChanges();
 
    entities.DeleteObject(table);
    entities.SaveChanges();
}

So Which is Better?

Well, that depends on what you want to accomplish but then, doesn't it always? For me, the LINQ to SQL solution is much cleaner because I'm simply not going to use all the other goo that the Enterprise Framework includes. Plus, the LINQ to SQL solution can use an XML fragment so I can bury that mapping piece wherever I want to, including in inline code. EF requires a file reference so those files have to be either in the assembly resources or on the file system. EF also allows you to leverage Asp.Net Data Services but that's a topic for another post entirely...

Tags: , , , , , , ,

Programming

Printing Reporting Services 2005 Reports

by Jacob 8. December 2007 16:21

Invoice About a year ago, I had the "opportunity" to automate batch printing for a couple of reports for my small company. Printing an invoice and a packing slip for 100+ orders at a time practically begs to be automated. Now, because we have specific needs with regards to the order they print in and what gets stapled to what else, this wasn’t something you could build into the reports themselves. Because the reports were originally programmed in Crystal Reports, I descended into the Crystal cesspit and just made it happen. If you’ve ever tried to automate report data access and printing in CR, you might know some of the pain I found there.

Well, we’ve been working on kicking Crystal out. Reporting Services has its quirks but for the most part it has been a huge relief to be able to handle reports in a central server with scheduled delivery in multiple formats without having to deal with Crystal’s (sorry, "Business Object’s") quirky proprietariness, temperamental processing, or extortionate enterprise server. Anyway, delving into automating report printing in Reporting Services revealed something of a blind spot in that service—there’s no built-in way to print a report on the server.

Automating report printing for RS is still ten times easier than it was in CR. Even so, it’s a pain. Google wasn’t much help in slaying this particular dragon, though there’s a blog post by Bryan Keller from February 2004 about using C# to print RS 2000 reports that turned out to be useful. It turns out that printing is a tough nut to crack, starting with who is responsible for kicking off the print job (the client, the report server, or a print server). It’s not really surprising that RS decided to punt on this one.

A Solution (of sorts)

I ended up using the RS web service to generate the report and send it to me in EMF format. I’m using VS 2008 now, so this was a good time to test some of that new-fangled technology I’d heard so much about.

WCF WTF?

My first hurdle was trying to use Windows Communication Foundation to access the web service. This isn’t actually my first project using WCF—it’s my second. My first project was against the Dynamics web service for Great Plains, which is where I learned that WCF is tricky when using integrated windows security. I thought that I had slain that beast, but the configuration options I worked out for the GP Web Service flat-out didn’t work when hitting against the RS web service. I got authentication errors until I was pulling my hair out. (See update below)

I wish I could tell you how I managed to overcome the problem, but I can’t. I dropped back to using old-school web service objects. This is an easy option to miss because when adding a Service Reference you have to hit the "Advanced..." button and then notice the "Add Web Reference..." button from there.

I regret this necessity because the WCF generated objects allow you to keep track of your RS session manually by obtaining and passing a session ID. The web service objects don’t expose that those methods and that’s a shame. There’s probably a way to reconcile this feature disparity either by figuring out how to get WCF to work or by finding the right buttons to push on the web service configuration, but this simply wasn’t that high a priority for me. This isn’t going to be an application that more than one person uses at a time and the volume will be frankly low so I can let RS keep track of the session by IP if it wants to (it’s a mostly unfounded assumption that this is how RS keeps track of your session. I saw one reference to something that looked like it was tracking me by IP, but again it wasn’t a high-enough priority for me to track it down to be sure).

I Can Print That Report in Four Calls

So here’s the messages needed (roughly) for pulling a report from RS over the web service:

  1. Load the report. This is, quite frankly, the easiest call.
    Client.LoadReport(ReportLocation, null);
  2. Set the parameters. This one isn’t that hard either.
    private void setParameters(Dictionary<string, string> reportParameters)
    {
        if (reportParameters.Count > 0)
        {
            List<ParameterValue> parameters = new List<ParameterValue>();
            foreach (KeyValuePair<string, string> param in reportParameters)
            {
                ParameterValue paramValue = new ParameterValue();
                paramValue.Name = param.Key;
                paramValue.Value = param.Value;
                parameters.Add(paramValue);
            }
            Client.SetExecutionParameters(parameters.ToArray(), null);
        }
    }
  3. Run the report. Again, not a tough call, but if your format is an EMF image format (and mine is), then this only returns the first page. Additional page references are given in the StreamIds parameter which let you retrieve them separately.
    private List<Metafile> renderReport(out string[] streamIds)
    {
        byte[] result;
        string ext, mimeType, encoding;
        Warning[] warnings;
        result = Client.Render(Settings.Default.ReportFormat, Settings.Default.DeviceInfo, out ext, out mimeType
            , out encoding, out warnings, out streamIds);
    
        List<Metafile> pages = new List<Metafile>();
        MemoryStream memStream = new MemoryStream(result);
        pages.Add(new Metafile(memStream));
    
        return pages;
    }
  4. Retrieve the extra pages. Nothing exotic once you know it has to be done. Call for each StreamId returned in the last call.
    private void renderStream(string streamId, List<Metafile> pages)
    {
        string mimeType, encoding;
        byte[] result = Client.RenderStream(Settings.Default.ReportFormat, streamId, Settings.Default.DeviceInfo
            , out encoding, out mimeType);
    
        MemoryStream memStream = new MemoryStream(result);
        pages.Add(new Metafile(memStream));
    }

You can see that I put the requested format and the DeviceInfo into my app.config. The format is simply "IMAGE", and the DeviceInfo only indicates EMF as the format:

<DeviceInfo><OutputFormat>emf</OutputFormat></DeviceInfo>

Note that even though that’s an XML fragment, it’s passed as a raw string, so there’s no need to get fancy.

I originally went with TIFF as the format, but ran into some issues that are big enough I’ll go into it here to spare you some pain. TIFF seems like a better format because it will send you the entire report in a single pass and thus allow you to cut the number of calls significantly for multi-page reports. The problem with TIFF is that a) printing multi-page TIFFs in .Net is a pain and b) the file size is huge. The default image resolution for TIFF is a measly 96dpi so you have to add how nice you want it to look in the <DeviceInfo> tag. Since my reports have barcodes in them, I needed some significant dpi (I didn’t get decent results until about 2400). That additional dpi comes with a huge file size hit such that transferring the image took a couple seconds for even a single page. EMF as a format transfers the image as drawing vector information so you can take care of scaling on the client. That makes EMF orders of magnitude smaller (and hence faster once all is said and done).

I ended up stuffing all of this in a single class (ReportManager) that I’ll link to at the bottom of this post. I’ll actually link the whole project because I was smart enough to encapsulate this stuff for reuse.

Printing

Printing turned out to be a whole lot easier than I expected using GDI+. Bryan Keller’s article referenced above was helpful but I didn’t need half of his complexity. After populating class variables "emfImage" as a List<MetaFile> and "printer" as a simple string you end up with this (yes, I know I’m abusing ArgumentException).

public void Print()
{
    if (emfImage == null || emfImage.Count <= 0)
    {
        throw new ArgumentException("An image is required to print.");
    }

    printer = printer.Trim();
    if (string.IsNullOrEmpty(printer))
    {
        throw new ArgumentException("A printer is required.");
    }

    printingPage = 0;
    PrintDocument pd = new PrintDocument();
    pd.PrinterSettings.PrinterName = printer;
    pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
    pd.Print();
}

private void pd_PrintPage(object sender, PrintPageEventArgs e)
{
    Metafile page = emfImage[printingPage];
    e.Graphics.DrawImage(page, 0, 0, page.Width, page.Height);

    e.HasMorePages = ++printingPage < emfImage.Count;
}

I ran into EMF scaling issues when I tried to skip including the width and height on the call to DrawImage, I’m not sure why. Again, I stuffed all this into its own class (PrintManager), though I didn’t bother isolating it in a separate library project.

Wrapping Up

I’ve put both the project source and just the binaries up for download. Note that I never actually tested the RunMultiple methods as they weren’t needed for this project. Yeah, that’s sloppy of me and if this were a commercial project or intended to be absolutely stable I’d have been more thorough.

* UPDATE: Okay, I couldn't leave the WCF thing alone—I don't like being beaten by a mere computer. As usual, finding the eventual answer always makes me feel pretty stupid, and this is no exception. The key component (after getting the client configuration correct in <basicHttpBinding> as this:

<security mode="TransportCredentialOnly">
  <transport clientCredentialType="Windows" />
</security>

was to set the right Token ImpersonationLevel:

service.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

Once that was taken care of, things worked out much better.

Technorati Tags: ,,

Tags: , ,

Programming

Dependency Injection

by Jacob 7. August 2007 15:08

Dependency Injection is a design pattern used to abstract a provider from the class using it. Specifically, the calling class assumes responsibility for managing the provider instead of the class being called. Data access is a classic example of a provider that can be injected into classes that use it. If you decide to implement the DI pattern in a data access project, the most common method of doing so is to add an interface parameter on the constructor of each class that needs data access.

A C# Example

A class that accesses data might look like this (if it were programmed by chimpanzees. Or for an illustrative example.)

Original Orders

I’m using the provider factory to pull the connection details from the application configuration file but otherwise this is pretty standard. Getting the data would require creating the object and calling GetData.

CallOrders
Dependency Injection

Dependency Injection would have me change the base class so that I pass an interface into the constructor. In this case, I can probably choose whether I inject the DbProviderFactory or DbConnection, but since DbConnection already has a handy interface, that’s definitely the best way to go:

DIOrders

The benefit to this pattern is that the class is now disconnected from the data provider. The disadvantage is that now my calling code has to handle the provider.

DICaller

Dependency Injection Dissected

Functionally speaking there’s not really that big a difference between the original version and the one with the dependency injected. In all, the actual complexity of the code is a wash in my opinion.

Either way, I’m better off with an abstracted data provider (as handled in the factory classes). Either way, I need to make sure the project is consistent in how it creates the access providers (I’d probably create an internal utility class with a static method to pull down the connection, so don’t let the extra lines above distract you).

That said, dependency injection doesn’t scale well and creates opportunity for future versioning pain should you find you later need to add providers. What if, for example, I need two data connections instead of one for my class because some of my data is being pulled from a second data source. I would then need two parameters on my constructor. I could move the injection point to the methods instead of the constructor so that only the affected methods have the signature change (a not-uncommon DI method if only a small number of methods have the dependency), but generally that just pushes my problem down to where it affects more code.

And yeah, providers shouldn’t change often and there shouldn’t be more than one or two so this isn’t a huge concern. I just hate breaking encapsulation and even a small hit to your orthogonality can be significant if you find you ever have to change it.

Dependency Injection’s Natural Domain

The real reason that DI has become so popular lately, however, has nothing to do with orthogonality, encapsulation, or other "purely" architectural concerns. The real reason that so many developers are using DI is to facilitate Unit Testing using mock objects. Talk around it all you want to, but this is the factor that actually convinces bright developers to prefer DI over simpler implementations.

I do wish that people would admit that DI doesn’t have compelling applicability outside of Unit Testing, however. I’m reading articles and discussions lately that seem to take the superiority of DI for granted. And I’ve read mock object examples that seem a little bit condescending about dependency injection--as if your projects should already incorporate this technique. I wonder if this is a defensive reaction because the authors of the examples don’t want to have to justify making you fundamentally alter your coding habits and re-write all of your existing code just so that you can use their pet objects.

Superior .Net Mocking

All of this becomes particularly exasperating in the dead silence regarding TypeMock. I blogged about this product as soon as I found it because their claims are simply stunning. TypeMock claims to allow you to mock objects used by your classes without having to expose those internal objects at all.

I have completed a project using TypeMock for my Unit Testing and I can verify that they are correct.

No interface creation or injection required. No dependency injection at all. No change to how I want to create my objects. No orthogonality issues hidden like a time-bomb in my code, however tiny. TypeMock uses reflection to intercept pesky calls and has robust assert, parameter, return object and verify options. The ability to select which calls to mock and which to let the original objects handle is an outstanding unlooked-for bonus.

Best of all, TypeMock is free to use. Yeah, it’s easier to use their professional and/or enterprise products because there are improved ease-of-programming objects in those editions, but their community edition has all of the actual functionality and none of the cost.

What Gives?

So tell me; what gives? Why the resounding silence around this tool? If it works, why isn’t every .Net developer on the planet talking about it. If it doesn’t why aren’t they reviling TypeMock for taunting us so cruelly? I’m serious. Why isn’t this sucker taking the Unit Testing space by storm? And why am I still hearing about the virtues of a pattern whose sole perceptible benefit is allowing mock objects in Unit Tests?

Tags: , , , , , ,

Programming | Software

scruffylookingcatherder.com

Information

    Recent Posts

    Calendar

    <<  September 2010  >>
    MoTuWeThFrSaSu
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    View posts in large calendar
    Disclaimer
    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2010 Scruffy-looking Cat Herder