Doing tiers with WCF
16 May 08 02:48 PM | William | 1 comment(s)

Because the nomenclature of WCF is often different then the technologies it consolidated, one of the problems you'll likely encounter when moving to it is figuring out how to do the same things you were doing before.  That's probably not the right way to phrase it, what i mean is, how do you implement the WCF equivalent?

With plain old web services, there's more that's similar than different so it's not a big challenge. But architecturally, things aren't as similar as they may appear. And if you try to create a similar architecture for Remoting (you know, that technology Counterfeit ASP.NET Gurus cower away from b/c it's over their head) or MSMQ, things are more pronounced, at least they seem to be.

At the risk of sounding like a cheerleader for the new latest greatest technology from MS, I will say that once you get into WCF, you'd be hard pressed not to find it much simpler and intuitive than any of the older technologies.  I personally have a pretty big investment in Remoting, WS and WSE 2.0 and 3.0.  Letting go of all of that and starting new is a little daunting. After all, while I know I can get there in WCF, it was hard at first coming up with time estimates and even harder making sure that what I was doing was the 'same' as the Remoting or WSE equivalent. You'll likely find yourself in the same scenario but if you just stick it out for a little while, I can promise you'll find yourself astounded at how much easier it is to do things.

I worked on a very large application for the state of South Carolina a few years ago. There was an ASP.NET Front end.  From there, it would call out to a Application Server which hosted the Business Layer. That Business layer in turn called a generic DAL. The DAL in turn called a provider specific DAL.  The provider specific DAl would then call the database.  There was also another facade implemented via WS that used DIME and a few other WSE specific features (by virtue of saying it used DIME, you can tell it was a while ago b/c MTOM has been where it's at for a while now).

All of the layers could be run on one machine or, you could move them out as needed. For scalability this was a great infrastructure. And it helped greatly with security.  Many of the apps that were built for the state were implemented with an ASP.NET Front end that talked directly to the database.  This forced the IT department to make many concessions with respect to the firewall and DMZ and if performance started suffering, the only solution was buying more server resources or getting a new server.  Well, that debate has been had and is over - for large scale applications that need to scale, the front end -> database model is lame.

Trying to implement this n-tier approach in WCF was so easy though it was really amazing.  I simply created a WCF Service library for each tier.  There was a facade which is what the asp.net front end of Winforms front end would communicate with.  This was a service itself which in turn calls out to the Business tier/service.  The Business tier/service is another WCF Service library which calls a Data Tier/service.  That tier is another WCF Service library which can call out to any of the provider specific tiers. Each of those in turn can talk to the database directly. So, you can easily run this application in a manner that means the web server hosting the ASP.NET UI never talks to the db directly.  You can however, by simply changing a few configuration section values, run everything on the same machine (if you wanted).

WCF allows you to run all of the services InProcess (Juval Lowy has an excellent discussion of this in his Programming WCF Services book - which is as good of a book as you'll find).  If they will all be run on the same machine, you can simply used the netNamedPipeBinding

So using the example I mentioned above, the Facade service(s) serves as the Server for the Winforms client or ASP.NET front  end. At the same time though, it is a client of the Business Tier (and you certainly could make this the business tier if you wanted to). I discuss handling it as a client Here.  So the wcf library holding the business logic becomes a server to the facade service, but serves as a client to the generic data tier.  The generic data tier is a server to the business service, but is a client of the provider specific DAL.  The provider specific DAL's are not clients to anything in the WCF sense, but technically they are for they call out to the db server.

B/c many of these tiers simply call other tiers, the interface/contract they use is the same. It could be different if you had reason for it to be, but by using the same contract, you can greatly simplify things. In this instance, I created a library which was shared with every single library, that hosted the contracts.  Looking at the code snippet from my previous article, you can see that the Interface implemented is the same throughout:

The article I pulled this from it available here

ChannelFactory<IStripper> stripperFactory = new ChannelFactory<IStripper>("NamedPipe");
IStripper serviceInstance = stripperFactory.CreateChannel();
using (serviceInstance as IDisposable)
{
   Console.WriteLine(serviceInstance.Bounce(BounceLevel.Woot));
   Console.WriteLine(serviceInstance.SlideDownPoll(PoleManeuver.LookMaNoHands));
   Console.WriteLine(serviceInstance.MilkSuckerForCash("Peter Griffin"));
}

Or where I was using the client proxy...

public partial class PurePlatinumServiceClient : ClientBase<IStripper>, IStripper
    {...}

So using that same methodology, the client configuration file looks like this (I'm leaving out everything unrelated to WCF):

<system.serviceModel>
   <client>
     <endpoint address="net.pipe://localhost/StripperService" binding="netNamedPipeBinding"
         bindingConfiguration="" contract="Cuckooz.Sample.WCFStripClub.IStripper"
         name="MainPipe" />
   </client>

 

No server configuration is needed b/c this is the client tier hence, it does no serving at all.  Now, look at the facade's configuration (again, the code is identical at each tier for the most part. Each tier may do some of it's own validation , but at the end of it, it's using the return base.Channel.MethodName(Params) if I use the clientproxy or calling the method directly if I use the interface.

Now, let's look at the configuration of the Services.  For the actual business implementation, I called each service a slightly different named, like ProductBusinessAPIService, ProductGenericDALService, ProductDALSpecificService and the like.  The interface remains the same in each case, only the name of the service that I'm exposing it as changes.  If I used different interfaces, then obviously those would need to change in the configuration, but little more than that would need to be changed (actually, nothing more). The thing to notice is that other than the client and the data service, each of them is functioning as both a client and a server.  They are clients to the next service in the chain and a server to the one before it. So the facade is a server to the ui client app, but a client of the business service. The business service is a client of the generic DAL but a server to the facade. The generic DALis a server to the business server but a client of the specific DAL. 

If you saw that say the specific DAL was eating a ton of resources, you could simply move it to another box. You'd need to change the bindings to a different mechanism b/c namedpipes won't work across machines but you'd simply need to add a Endpoint that uses the NetTcpBinding for instance, and other than the address, they'd look virtually identical to the existing named pipe equivalent. So without changing a line of code, you could move each piece to a different box (unless you consider config values 'a line of code'. 

So here's the Facade Service:

<system.serviceModel>
    <client>
      <endpoint address="net.pipe://localhost/StripClubBusinessService" binding="netNamedPipeBinding"
        bindingConfiguration="" contract="Cuckooz.Sample.WCFStripClub.IStripper"
        name="ClientPipe" />
    </client>
    <services>
      <service behaviorConfiguration="Cuckooz.Sample.WCFStripClub.StripServiceBehavior"
        name="Cuckooz.Sample.WCFStripClubs.StripperService">
        <endpoint address="mex" binding="mexHttpBinding" name="MainMex"
          contract="IMetadataExchange" />
        <endpoint address="net.pipe://localhost/StripperService" binding="netNamedPipeBinding"
          bindingConfiguration="" name="MainPipe" contract="Cuckooz.Sample.WCFStripClub.IStripper" />
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:8731/blahblah/facade/GenericService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>

    
<serviceBehaviors>
        <behavior name="Cuckooz.Sample.WCFStripClub.StripServiceBehavior">
        
<serviceMetadata httpGetEnabled="True" />
          <serviceDebug includeExceptionDetailInFaults="True" />
        </behavior>

      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

 

So here's the BusinessService:

<system.serviceModel>
    <client>
      <endpoint address="net.pipe://localhost/StripClubDataService" binding="netNamedPipeBinding"
        bindingConfiguration="" contract="Cuckooz.Sample.WCFStripClub.IStripper"
        name="DataPipe" />
    </client>
    <services>
      <service behaviorConfiguration="Cuckooz.Sample.WCFStripClub.StripperServiceBehavior"
        name="Ger911.HCStandard.Core.API.StripClubBusinessService">
        <endpoint address="mex" binding="mexHttpBinding" name="Mex" contract="IMetadataExchange" />
        <endpoint address="net.pipe://localhost/StripClubBusinessService" binding="netNamedPipeBinding"
          bindingConfiguration="" name="MainPipe" contract="Cuckooz.Sample.WCFStripClub.IStripper" />
        <host>
          <baseAddresses>
            <add baseAddress="
http://localhost:8731/blahblahbalh/CuckoozStripClub/StripperService/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Cuckooz.Sample.WCFStripClub.StripperServiceBehavior">

       <serviceMetadata httpGetEnabled="True" />
        <serviceDebug includeExceptionDetailInFaults="True" />
      </behavior>

</serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Now here's the Generic Data Service:

 

<system.serviceModel>
  <services>
    <service behaviorConfiguration="Cuckooz.Sample.WCFStripClub.StripClubDataServiceBehavior" name="Cuckooz.Sample.WCFStripClub.StripClubDataService">
      <endpoint address="mex" binding="mexHttpBinding" name="Mex" contract="IMetadataExchange" />
      <endpoint address="net.pipe://localhost/StripClubDataService" binding="netNamedPipeBinding" bindingConfiguration="" name="DataServicePipe" contract="Cuckooz.Sample.WCFStripClub.IStripper" />
      <host>
        <baseAddresses>
          <add baseAddress="
http://localhost:8731/blahblah/CuckoozGenericDal/GenericDalService/" />
        </baseAddresses>
      </host>
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="Cuckooz.Sample.WCFStripClub.StripClubDataServiceBehavior">
                 <serviceMetadata httpGetEnabled="True" />
            <serviceDebug includeExceptionDetailInFaults="True" />

      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

 

Finally, here's the configuration for one of the provider specific (Sql Server) Data Service:

<system.serviceModel>
  <services>
    <service behaviorConfiguration="Cuckooz.Sample.WCFStripClub.StripClubSqlServerServiceBehavior" name="Cuckooz.Sample.WCFStripClub.StripClubSqlServerService">
      <endpoint address="mex" binding="mexHttpBinding" name="Mex" contract="IMetadataExchange" />
      <endpoint address="net.pipe://localhost/StripClubSqlServerService" binding="netNamedPipeBinding" bindingConfiguration="" name="DataServicePipe" contract="Cuckooz.Sample.WCFStripClub.IStripper" />
      <host>
        <baseAddresses>
          <add baseAddress=
http://localhost:8731/blahblah/CuckoozGenericDal/SqlServerDalService/ />
        </baseAddresses>
      </host>
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="Cuckooz.Sample.WCFStripClub.StripClubSqlServerServiceBehavior">
        <serviceMetadata httpGetEnabled="True" />
        <serviceDebug includeExceptionDetailInFaults="True" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

---------------------------------------------------------------

In this case, I switched something I was doing in the real world to make it a little more entertaining (and thereby not divulging specifics of a client project).  The real application is a little more complex and includes some other services which are employed as well by each layer - for instance, a crypto service and one to serve up images and documents.  The Generic DAL service is one that we could probably easily do without, but the goal is that if the client wanted to change their DB to Oracle or something else, would could simply develop the service, deploy it, and add endpoints pointing to it.  In that case, we could change the whole mechanism without changing any code or causing any visible interruptions other than the initial switchover which would be miniscule.  By using an example where there are so many moving pieces, it really brings home home much flexibility you have using WCF and how easy it is to implement. Most applications one works on won't have anywhere near the demands for scalability that are in place here (and there are a few other things that dictated this architecture which I don't need to go into). The point is that if you only had one or two service tiers, it would be all that much easier.  Just configure each piece as either a client, a server or both. If you use a shared assembly to hold your client proxies and/or your interfaces (in most cases, I've found this to be beneficial b/c the size of these classes are typically pretty small, so you can get consistency without having to really worry about bloating the footprint by sharing the assembly over and over. And besides, you needed a contract anyway, so there'd only be bloat if you had additional items that you weren't using. in this instance, I'm not introducing anything that I wouldn't have needed anyway).

Oh yah, one other thing... I have a little pet peeve about string literals. They drive me nuts, especially in cases where they are used for session variables.  I'd highly recommend creating a constants class in your shared assemblies library.  For each Endpoint you plan on needing, create a string constant that you'll use as the name of the endpoint. I started out calling it "... Pipe" but realized that was misleading b/c in many cases, I'd be using Tcp instead of Named pipes, so I just moved to something a little more generic.  The naming isn't what really matters, it's the consistency, but having clear and intuitive names doesn't hurt ;-). So doing something old school like this (think back to session variables in ASP.NET):

 

public static class ConfigurationConstants
{
    public const String Localhost = "localhost";
    public const String NamedPipeEndpointName = "MainPipe";
    public const String ClientBusinessServiceEndpoint = "ClientBusinessPipe";
    public const String ServerBusinessServiceEndpoint = "ServerBusinessPipe";
    public const String ClientGenericDataServiceEndpoint = "ClientGenericDataPipe";
    public const string ServerGenericDataServiceEndpoint = "ServerGenericDataPipe";
}

 

I'm trying to make this into a real demo app that's documented and can be done in steps - basically trying to turn it into a full walk-through. So I'm documenting it as I go along. I've gotten it completed through here - but I'm going to add Security, support for MSMQ and a few others (just to show you don't need to change the code you write in most cases) and use the Enterprise library for logging, security and data - if you want the code for this part up through here, just email me privately. I should have the whole thing done in a few weeks. So be advised, i can give you the code, but I don't have much done in the way of explanations in the code - although I will shortly.

---------------------------

Also, if you're interested in WCF, times are really good.  I've read every book except for Michelle's (and that's next on the list b/c I'm sure it's going to be great) and I have to say, they are all good.  It's really a case of "you can't go wrong" whichever one you buy. I'd recommend all of the following - in no particular order:

Programming WCF - Juval Lowy

Essential Windows Communication Foundation (WCF): For .NET Framework 3.5

Inside Windows Communication Foundation

Pro WCF - Practical Microsoft SOA Implementations

Windows Communication Foundation Step by Step

Professional WCF Programming

Windows Communication Foundation Unleashed

Mobile Application Development Webcast Info
16 May 08 01:04 PM | William | with no comments

Constanze just posted this about a 5 part webcast series he and others like Maarten Struys will be conducting on mobile application development:

-----------------------------------------------------------------------------------------------

Just wanted to remind everybody that our 5-part Webcast series on Mobile Application Development is starting today. This morning, Maarten Struys and I will provide an introduction into Mobile Application development, we'll show you all the cool tools that are available, plus there will be some demos. So check it out.

The Webcast will start today, Friday, April 16 at 11 AM PST. Here's the link to register for it: Register Here.

See you at the Webcast today!

 Constanze

ChannelFactory.CreateChannel goes to the Gentlemen's Club
12 May 08 06:07 PM | William | 4 comment(s)

Currently, I'm tasked with getting some people up to speed on .NET 3.5 as well as WCF.  WCF is really cool and it's easy to fall in love with, but it's also easy to cause you to sleep when you're first learning it. So instead of walking through Hello World, I changed course. 

Basically, we're using an architecture where the Business Layer and Data Layer are services. In most cases, we'd run them on the same machine, in Proc. In other cases, when scalability is more of an issue, we'd need to separate them out.

Creating Services is nothing special and other than a few attributes (ServiceContract, OperationContract, often DataContract and/or DataMember or EnumMember) and an interface, there's no real way to tell a wcf service from any other class (and since most of those attributes should go on the interface, the class itself shows no sign of being a service other than the interface implementation).  One thing though, when you add a WCF service to an application through VS, it will stick the service class and the corresponding interface into the same project.  I typically move my interfaces out of the project and into a library so that I can share them.  In a case where your business methods just call the dal's methods, the interfaces/contracts will be the same so you may be able to share them.

WCF gives you similar hosting options to Remoting and Web Services.  You can add a Service Reference and have svcutil.exe generate a proxy class which is virtually identical to what you did with web services. Hosting them is the easy part and if you can run a Console application and remember to put Console.Readline at the end of it, you can start a service host.  There's about a zillion examples out there and it's usually one of the first things covered in WCF so I'm leaving that alone for now.

On the client, you can add a service reference as I said. However that is not without its problems and you may want a little more flexibility. If you want to create your own proxies, there are two primary methods (outside of svcutil related approaches). Let's say you have the following interface:

namespace Cuckooz.Sample.WCFStripClub
{
   [DataContract]
    public enum BounceLevel{

       [EnumMember]
       Lame,
       [EnumMember]
       Woot,
       [EnumMember]
       YeahBaby
    };

    [DataContract]
    public enum PoleManeuver{
        [EnumMember]
        Standard,
        [EnumMember]
        LookMaNoHands,
        [EnumMember]
        UpsideDownLookMaNoHands
    };
    [ServiceContract]
    public interface IStripper
    {
        [OperationContract]
        String Bounce(BounceLevel bouncin);
        [OperationContract]
        String SlideDownPoll(PoleManeuver maneuver);
        [OperationContract]
        long MilkSuckerForCash(String customerName);
    }
}

One approach is to create your own Proxy class , inheriting from ClientBase and passing in the type of the interface, while implementing the interface.  Pay attention to the implementations of this class:

namespace Cuckooz.Sample.WCFStripClub
{
    public partial class PurePlatinumServiceClient : ClientBase<IStripper>, IStripper
    {

        public PurePlatinumServiceClient() { }

        public PurePlatinumServiceClient(String endpointConfigurationName) : base(endpointConfigurationName) { }

        public PurePlatinumServiceClient(String endpointConfigurationName, String remoteAddress) : base(endpointConfigurationName, remoteAddress) { }

        public PurePlatinumServiceClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) { }

        public String Bounce(BounceLevel bouncin)
        {
            return base.Channel.Bounce(bouncin);
        }

        public String SlideDownPoll(PoleManeuver maneuver)
        {
            return base.Channel.SlideDownPoll(maneuver);
        }

        public long MilkSuckerForCash(String customerName)
        {
            return base.Channel.SlideDownPoll(customerName);
        }
    }
}

Note that b/c we are passing in the interface as a generic type parameter to ClientBase, we can refer to it through base.Channel.MethodName.

You will need to have an endpoint configured in order to call the service and you should give the endpoint a name to make things easy.  In this case, I have a namedPipe endpoint configured named "NamedPipe". With that in place, you simply need to create an instance of your proxy and have at it:

PurePlatinumServiceClient dancerProxy = new PurePlatinumServiceClient("NamedPipe");
Console.WriteLine(dancerProxy.Bounce(BounceLevel.YeahBaby));
Console.WriteLine(dancerProxy.SlideDownPoll(PoleManeuver.UpsideDownLookMaNoHands));
Console.WriteLine(dancerProxy.MilkSuckerForCash("Peter Griffin"));

If you are going to create your proxies like this, do yourself a favor and use CodeSmith, some other template, or if you're just really hard up, copy and paste where applicable - it'll save you a lot of time.

If you don't want to go this route though, you can skip the whole proxy altogether.  Using the ChannelFactory class, you can specify the same interface we used above and create a new ChannelFactory.  Remember to name your endpoints in the configuration file so that you can refer to them. Otherwise, you'll need to specify the endpoint hard code style - which is lame.  Once you've done that, you instantiate an IYourInterface object using the CreateChannel method of the ChannelFactory you just created.  Then, you should cast it to an IDisposable object and throw it in a using block, and have at it from there. Note, you don't have to use IDispose but the other approach is to cast it as a ICommuncationObject and then call Close.  For the money, it's easier and safer to just go the IDispose route. So the code below is functionally equivalent to the preceding block:

ChannelFactory<IStripper> stripperFactory = new ChannelFactory<IStripper>("NamedPipe");
IStripper serviceInstance = stripperFactory.CreateChannel();
using (serviceInstance as IDisposable)
{
   Console.WriteLine(serviceInstance.Bounce(BounceLevel.Woot));
   Console.WriteLine(serviceInstance.SlideDownPoll(PoleManeuver.LookMaNoHands));
   Console.WriteLine(serviceInstance.MilkSuckerForCash("Peter Griffin")); 
}

Either of these approaches provides a ton of flexibility. For instance, you can create several endpoints, look at the environment and then decide which endpoint you want to talk on, hence, which binding you are going to use. Similarly, if you had several services you could easily change the execution to use on over the other ones.  All in all it really couldn't be simpler and in this case, the hardest part of the equation is going to be setting up your configuration file properly.

If I have time tomorrow I'll post the next lesson which uses Duplexing, there's a lot of potential with this interface and service when you enhance it with duplexing ;-)

 

 

 

How cheap are SMS messages?
12 May 08 03:16 PM | William | with no comments

Normally, when you hear a price comparison and the govt is involved, it's some ridiculously expensive item from the govt. However in the case of the cost of SMS messages vs the cost of pulling data from the Hubbell, it's just the opposite  it's just the opposite.  Hat Tip:  http://www.odetocode.com/

Filed under:
Sql Server 2008, Intellisense and Backward Compatibility
08 May 08 01:28 PM | William | with no comments

Whitney is a little disappointed that the RTM version of Sql Server 2008 will not support backward compatibility with respect to intellisense...

The conversation related to what I felt was misinformation in various places about whether or not IntelliSense would be backward compatible.  Currently, CTP6 will support IntelliSense against a SQL 2005 or SQL 2000 instance.  This was exciting to me as I tend to work in multiple revs of the product.  As it turns out, the RTM version of SQL 2008 WILL NOT support this behavior.  Here is Eric's statement to why that is the case:

He's got a petition going to try to get the Sql Server 2008 team to include it at one point or another.  There's no shortage of items on the wishlists of Microsoft products, especially something like Sql Server 2008.  They look to the community to help determine what's going to make the cut, so if you care about this feature, take a few seconds to let the team know your opinion. There are no guarantees but they care very much about what customers want and this is one avenue to communicate with the directly.

 

 

let the team know your opinion. 

Filed under:
LINQ Gotcha
07 May 08 08:00 PM | William | 3 comment(s)

After a long hiatus, I was trying to figure out something cool or at least interesting to blog about.  I was having trouble figuring out what I wanted to write, but then one after another, I got a ton of ideas.

One thing I wanted to do for my current project was finding out if a specific ConnectionString was present in the <ConnectionStrings> setting of a .config file. This is a big oversimplification but it's close enough to explain. So I wrote the following:

var myVar = from cs in ConfigurationManager.ConnectionStrings
            select cs;

 foreach (var Mine in myVar)
 {
       Console.WriteLine(myVar);
 }

I knew the second I tried to write a where clause that there was a problem b/c intellisense wasn't showing anything I expected. When I tried to display some of the properties in the foreach loop, nothing was visible. I knew something was wrong. So I tried to compile and got the following error:

Could not find an implementation of the query pattern for source type 'System.Configuration.ConnectionStringSettingsCollection'.  'Select' not found.  Consider explicitly specifying the type of the range variable 'cs'. 

Well, that was helpful b/c I knew at least the problem was with the  range variable .  I wasn't sure what type of collection the ConfigurationManager.ConnectionStrings  property was so I decided to look it up just to be sure. (I also just wanted to make sure it was in fact some type of collection or another. I couldn't imagine that it wouldn't have been, but just wanted to make sure for purely superstitious reasons) Ok, so it's a ConnectionStringsSettingsCollection , nothing surprising there. Digging deeper I saw that ConnectionStringsSettingsCollection inherits from ConfigurationElementCollection . At that point, it all became crystal clear for I saw the following in the class definition:

public abstract class ConfigurationElementCollection : ConfigurationElement, ICollection, 
    IEnumerable

Do you see the problem? There's an IEnumerable but no IEnumerable<T>   . You see, the collection implements the non-Generic IEnumerable but not the Generic IEnumerable. Hence, a explicit range variable is in order to make this work.  I know I know, that's exactly what the error message recommended, but I didn't understand why at first and wanted to dig deeper into it. So bascially, here's what was needed to make it work.  Simply use the Cast<T>   extension method on the collection and well, that's it.

ConnectionStringSettingsCollection cfg = ConfigurationManager.ConnectionStrings;

var myvar = from cs in cfg.Cast<ConnectionStringSettings>()
                  select cs;
foreach (var mine in myvar)
{
    Console.WriteLine(mine);
}

Of course, you could just cut out some of the bloat and address the collection directly

var myvar = from cs in ConfigurationManager.ConnectionStrings.Cast<ConnectionStringSettings>()
            select cs;

foreach (var mine in myvar)
{
  Console.WriteLine(mine);
}

Whenever Intellisense doesn't do what you're expecting it to, that's the first tipoff something is wrong in your query.  Although my days of 2 day work weeks have come to an end temporarily, I'll try to find some time to blog the rest of what I was working on - there's so much you can do with LINQ that I often overlook.  And this is the first time I've come across the explicit range variable issue but I'm guessing it'll come up again, particularly if you use LINQ regularly.

 

 

 

Seasons changing again.
29 March 08 01:06 AM | William | 5 comment(s)

Things have been pretty hectic lately so I haven't really kept up with everyone as much as I'd like to.  The big announcement with me is that I'm leaving Magenic and taking a new position much closer to home.  I've really liked most every company I've worked for over the years, and have always made a lot of friends at work.  Magenic has been a lot different.  As a Magenic employee, you frequently hear about the Magenic 'family'.  Many times such phrases are little more than campy soundin cliche's.  I can honestly say though, it's been completey different at Magenic.  It really is as close to family as you can get without the real thing and it's a huge bummer leaving.  The problem is, i've been living a duel existence.  I work in Atlanta, have a residence here, but I live in Greenville.  Atlanta traffic is something to behold so unless I leave really early Friday's, I end up with maybe 2 hours with the Family on Friday, all  day Sunday, and then about 1/2 day Sunday.  Although I agreed to travel as much as needed, Magenic was aware of my situation and really went out of their way to minimize travel for me. In my tenure, I've only had one real travel gig and that was only 5 weeks. I had a few small ones, but they were two or three day engagements. Throughout all of this, I've been busy doing work for Microsoft, work which requires me to be in Redmond regularly. I've been tech editing books pretty much consistently and I'm in the process of writing another book.  All of it added up to a really busy private life.  Kim has been a saint about the whole thing but we all have our bending points. 

So today was my last day at the company.  Sunday is my last day at my current residence.  I'll certainly be around Atlanta regularly so I'm not leaving in any permanent sense.  And  b/c of what I'll be doing, I'll have a lot of free time.  Sahil had been instrumental in convincing me to go independent and i finally stepped up and did it.  I have a lot to learn about the whole 'running your own business' aspect of consulting, but to be honest, I'm a really late bloomer in that regard and it's about time I did it.

I was spending most of tonight getting ready for my code camp presentation tomorrow all the while packing and trying to get out of here.  I probably should have just hired movers but like cutting my own grass, moving is one of those things I always insist on doing myself.  If I keep up that philosophy though, I am pretty sure I have maybe 2 more moves left in me in this lifetime, b/c moving Sucks.

Anyway, as I was getting everything moved, everything started to sink in.  When I first came to Magenic, I was really scared of being a little fish in a big pond, and I was.  B/c of really helpful co-workers and really supportive management, I was able to build up my skills pretty quickly.  After 6 months I won Magenic's Consultant of the Quarter award which was a big honor for me.  Shortly thereafter I was promoted from Senior Consultant to Principal Consultant.  With that came the position as Technology Evangelist which really added a high cool factor to an already cool job.  When I first got to Atlanta, I hated it. I love big cities and have lived in a few, but I felt totally overwhelmed. Traffic was like nothing I've ever experienced and it seemed that you had to plan your day around traffic.  It was hard to make committments to be anywhere in the morning, afternoon or early evening b/c of traffic.  One flat tire on the side of the road magnified by rubbernecking could turn a 15 minute trip into a 1 1/2 one.  And there was always a flat tire or police officer pulling someone over.  Rubbernecking is a scourge and I don't know what can be done about it, but it has to cost zillions of dollars in lost productivity.  The weird thing too is that EVERYONE acknowledges how wrong it is. Everyone says it's terrible and everyone says they don't do it. Yet every time there's a guy pulled over on the road, traffic will be backed up for 5 miles or more so there's a disconnect somewhere. (Reminds me of the "Kids peeing in pool paradox".  Every time I mention that I don't go in public pools where there are children I get asked why. I say 'b/c kids pee in the pool. I'm sure adults do as well, but you just *know* that kids are doing it.  Immediately, people with children say "Well, my child would never pee in the pool!"  So self-reports indicate that absolutely 0 people's children pee in pools, yet there's a lot of child pee in pools, so where does it come from?  Same phenomenon seems to be in place with rubbernecking).  Anyway, I ended up getting a place with a great location, so I missed traffic both ways other than getting out of the Perimeter on Fridays.  Little by little I went from hating Atlanta to really loving it.  Then it turned into my favorite city to live in.  And now that it's acheived that place in my heart, I've got to move ;-(  To that end, I'm quite sure I'll be back regularly - there's just too much I've gotten accustomed to doing here and greenville is cool and all, but it's not Atlanta.

If you want to get a hold of me, you can use the Contact link above and shoot me your email address, I'll get back to you from there.  You can also reach me at Facebook , LinkedIn, or Twitter.

Anyway, I'll be fully moved in this weekend and Kim and I will be tying the knot shortly.  Since I'm going to have a lot more free time, I'll be able to blog all the different 3.5/LINQ/ Entity Framework/Synchronization Services stuff I've been working on and hopefully will be able to get back into the newsgroups a lot more consistently.

As much of a bummer as it is to leave Atlanta, I've always liked Greenville and I'll be able to see Paul and Jason a lot more, not to mention my friends in Augusta like Ben. Brian and Andy.  All in all this is going to be a good move, but leaving a city you love and a job you love in a company you love is never easy.

And by the way... although we have a pretty high volume of applications, Magenic is always looking for passionate and talented professionals.  If you are in the Atlanta area and looking to get into consulting, or looking to work for a company that will really help you develop your career, Magenic is definitely a place that you'll enjoy. I'd be glad to get you introduced if you have any interest there so just drop me a line if you want.

Grand Theft Auto IV
28 March 08 05:38 PM | William | with no comments

A really compelling trailer for it is available at Amazon.

The Associated Press' Double Standard
17 March 08 09:46 AM | William | with no comments

Exhibit A 

Whether it's legal, illegal, moral, immoral or whatever, it's not a good idea to post stuff on the internet if you don't want people using it without your approval.  The main reason is that if someone does use it against your wishes, it's really hard to detect in most cases.  By the time you do, it could have been indexed and copied so many times your head would spin. On top of it, attempts at making people take things down usually end up backfiring. Like many bloggers, I've personally found my posts on other people's blogs where they are taking credit for it. It used to annoy me.  Then I got ot the point that I figured it's not worth fighting b/c it would require a lot of ongoing energy.  My way of dealing with it is usually to create variable names or comments that are self referencing - so basically I give myself the link back.  If I wrote something though that I wanted to control, it would not be posted on my blog.

 Personally, since I make my living selling intellectual property, I have a tremendous amount of respect to other people's IP.  On the other hand, the doctrine of Fair Use is necessary and life without it would not be good.  It seems too often there are two extremes that people operate in.  On the one hand, if it's on your site, no matter how much legal verbiage you surround it with, they act as though they can take it and do with it what they please.  On the other hand, you have folks that post stuff that people reference which clearly falls under the domain of Fair Use and they start making all sorts of noises about it.

 If I can digress for a minute.  Most of us will require the services of a lawyer at some point or another. When a relative dies, when you buy a house, when you for a corporation etc, you'll typically want to enlist the services of an attorney.  On the other hand, most run of the mill folks only have limited dealings with an attorney (cost alone prohibits using a lawyer frequently).  I"ve had to use a laywer for a few different things in life but in each case, I needed on for different tasks. I don't ask the guy who did my house closing to run a patent search for me.  So I, do not have "a lawyer".  That brings me to my little rant point....  "You'll be hearing from my lawyer".  Whenver I hear this (I've only heard it twice in reference to something I did, but I've heard people in line at the Verizon store say that twice, and have heard people threaten it on other occassions to random people"), I always think "WTF Ever".  To have "my lawyer" typically means that you keep him on retainer.  Very few people have enough legal dealings to warrant keeping a lawyer on retainer for indefinite periods of time. So when I hear that, It warrants only a chuckle.  Even if you really do have a lawyer, you just sound stupid making such threats. If you are really going to get a lawyer involved, just do it.  And whatever you do, don't send ridiculous absurd threatening emails where you threaten frivolous litigation where you mention your big city lawyer over and over again, especially when you don't have a  lawyer, lied about everything in your email and don't have the money or grounds to file litigation. You'll just make a fool out of yourself.

 Ok, anyway... I think you ought to play it one way or the other, but you can't have it both ways. In order for a site like http://www.snappedshot.com/ to do what they do (Criticize and point out inaccuracies with photo journalism), they really need to show the images at hand. They don't charge money and they aren't presenting it as their own.  But if they just referred to the photos at hand, it would really diminish the effect. If they linked to the image, several problems would present themselves as well. But for the Associated Press to say he has no right to do this, and then go and snake "Kristins" photos, that's pretty shameless. Clearly they have a legal department and he doesn't. So they thought they'd just bully him around with their big city lawyers (unlike unemployed nuts who can't live without borrowing money from people and not paying them back). When they needed some images for their story though, they had no problem swiping them. And they were definitely under copyright so they engaged in sheer hypocrisy by doing this. 

Filed under: ,
Silverlight for Windows Mobile
17 March 08 09:16 AM | William | with no comments

Speaking of new features that should help Windows Mobile remain the dominant player in the market, a mobile version of Silverlight is going to be coming down the highway .

The good news:

  • Expected release is Q2 - 2008
  • You can use Expression Blend to develop it with.  So you won't need a new or additional IDE

The bad news:

  • It will be Silverlight 1.0

I know, the teeth on that horse you gave me are a little crooked.  Response time is really going to be the big factor here... if it's fast and works right, this is going to be a huge, HUGE, feature that will open many doors to mobile development. 

The Microsoft® Windows Mobile Line of Business Solution Accelerator 2008!
17 March 08 09:04 AM | William | with no comments

Rob Tiffany has got the details... . 

The main features include:

  • Intelligent resolution awareness
  • Synchronization Services
  • Windows Communication Foundations "Store and Forward"
  • MapPoint
  • LINQ
  • Custom Controls
  • Managed Stored Procedures and Triggers
  • Notifications and Online Help
  • Language Switching and Localization

Some of these (WCF, Synchronization Services) are a lot more thrilling than others but all in all it's a great step forward.  With that said, I think MS really needs to work on a few things. When the iPhones first came out, I was lucky enough to have one sent to me.  I liked it but didn't go gaga over it. After two days, I decided to sell it.  I think UI wise, it was far ahead of a typical SmartPhone although the PocketPC edition phones gave it a lot better run for the money.  But I know that my opinion is not typical. In fact, most iPhone users who have used or use Windows Mobile are really adamant about the superiority of the UI and usability.  I think some of that is b/c they are comparing a 500.00 phone with a much cheaper one in many cases but across the board, the iPhone does probably have the advantage.  Having started to toy with the iPhone SDK, I have to admit it's fairly easy to pick up (nowhere near as easy as the Compact Framework) so once more applications come out for it, it will make it all the more attractive to mainstream users.  I have a lot of faith in Microsoft though and nothing would please me more than for Windows Mobile 7.0 to work so well that my obnoxious iPhone owning friends will have to pipe down about the greatness of the iPhone.  The accelerator however, is definitely a step in the right direction.

Whitney Weaver is now blogging
11 March 08 05:38 PM | William | with no comments

My friend and co-worker,Whitney Weaver is now blogging at the Magenic blog site. Actually, he's been blogging for a little while now, I've just been a bum and not updated my blog in a while.  Although he's certainly an up and coming programmer, Whit's main area of expertise is data, so if you're a data guy (or gal), you should check out his site

More Posts Next page »

This Blog

News

    William G Ryan William Ryan Bill Ryan W.G. Ryan Charles Mark Carroll Charles M Carroll
    My Blog Juice Microsoft MVP
    Bill Ryan W.G. Ryan William Ryan
    Cuckooz' MySpace Page View Bill Ryan's profile on LinkedIn
    My Profile on Twitter
    Please note that this is my personal blog and the opinions expressed are my own. Also, comment moderation is about one of the least important things in my life so please keep that in mind. I can't vouch for the authenticity of any of the posters so please don't hold me accountable. And whatever you do, don't pretend to be Noted Option Strict Off expert and AspFriend Charles Mark Carroll when you post. Doing so will lead him to become apoplectic and write absurd accusatory posts about me that are as coherent and thought out as they are factually correct. He does a stellar job proving his reputation is well deserved and he doesn't need any help from you making himself look foolish. If I have to listen to him banging his spoon off of his high chair one more time, I'm going to burst into flames so please don't make that happen!

    My other sites

    Cool Stuff

    Book Stuff

    Security

    ORM

    Data Access

    Funny Stuff

    Compact Framework Stuff

    Web Casts

    My KnowledgeBase Articles

    My MVP Profile

    Design Patterns

    Performance

    Debugging

    Remoting

    My Fellow Authors

    My Books

    LINQ

    Misc

    Speech

    Syndication