Contact
Send mail to the author(s) Email Me

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In
Navigation

Tag Cloud
.NET Framework (31) AJAX (9) ASP.NET (16) ASP.NET MVC (3) C# (32) Cloud (2) Database (6) Dev Community (2) Dev Tools (5) Enterprise Library (1) Futures (2) General (6) Javascript (7) LINQ (2) Mobile (1) MSDTC (5) Quotes (3) SQL (3) Transactions (4) Visual Studio (3) WAS (2) WCF (19) WIF (1)

Archive
<August 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

Categories

Blogroll
Home Feed your aggregator (RSS 2.0)
# Sunday, June 29, 2008

Enterprise applications store their data in a relational database. Our code reads the data stored in tables with many complex joins and business rule laden queries. We take the results of those queries and construct an equally complex business entity that is used by our application logic. Most developers, myself excluded, hate working with the database. Writing, modifying, or even seeing T-SQL causes some developers to itch. LINQ to SQL serves as a partially effective Hydrocortisone to relieve the itch. But they still need to maintain the schema, write SQL-mindful LINQ queries, and deal with the constant DataContext updates.

 

Imagine a world where you no longer need to translate your complex business entities to and from relational tables.  A world where there is no database backing store. A world where we create our business entities and store them in memory. Even better, in memory on a shared resource. Does it sound like an inconceivable futuristic developer heaven? Well it probably is, but this is really cool stuff in the works.

 

Enter the Microsoft project code-named "Velocity." The blurb on the overview page reads:

"Velocity" is a distributed in-memory application cache platform for developing scalable, high-performance applications. "Velocity" can be used to cache any CLR object and provides access through simple APIs. The primary goals for "Velocity" are performance, scalability and availability.

I have been working with the Digipede Network, the leading grid computing software solution, for a few months. The Velocity architecture sounds remarkably similar to Digipede's. I have seen the great benefits of the Digipede Network and have high expectations for Velocity.

The Digipede Network, for those of you that haven't seen it yet, consists of a central Digipede Server and one or many Digipede Agents. The server receives client requests and assigns tasks to the agents. The client uses the Digipede API to communicate with the server. The API pretty much wraps client-to-server and server-to-client WSE2 web service calls. This architecture allows you to take almost any CPU-intensive process and spread the workload among tens or hundreds of commodity or server grade machines. The result is a very high performing and easily scaled system with few code changes from what you do today.

Digipede Network Diagram:

Digipede Network Diagram

Digipede only works in this configuration, while Velocity has two proposed deployment models. You can have a "caching tier", similar to Digipede's Server and Agent configuration, or you can house Velocity as a Caching Service directly in IIS7. I don't know how communications will be handled between the client API and the "caching tier", but I assume it will be some sort of service calls (WCF perhaps). All CLR objects stored in the Velocity cache must be marked [Serializable] just as task worker classes must be to work with Digipede.

The Velocity API looks simple enough too. It exposes intuitive Get() and Put() methods where you call the cache by name. I can see how versioning of the cached objects might get tricky. Your application will also need a new configSection that specifies the deployment mode, locality, and also contains the list of cache hosts. As this is a distributed solution, the standard virtual machine playground doesn't work too well to really test this out.

This looks promising, and I'll be following the progress of the project closely.

Download Velocity

Download the Velocity CPT 1 samples

Saturday, June 28, 2008 11:11:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments [7]   .NET Framework | C# | Database  | 
# Saturday, June 21, 2008

A few months after SQL 2005 was released and hit the productions servers, some people started experiencing some odd behavior in their stored procedures. Simple stored procedures that normally return in 0 seconds would take upwards of a minute to return. Even more strange was the fact that the same query, outside of a stored procedure, would still return in 0 seconds.

It never affected me personally... until today. Three years late to the party. It's funny how much more interested I am in the causes and solutions for this apparent problem when it affects me. "Parameter Sniffing" is the term Microsoft uses to describe the feature that causes this odd behavior. While it appeared as an issue when I encountered it today, I found that the feature is not only well-intentioned but quite useful.

The execution plan is generated and cached the first time your stored procedure is called. When the execution plan is being created, SQL Server reads the input parameters and uses them to optimize the execution plan for those parameters. This is called "parameter sniffing." If the input parameters used in the first call to the stored procedure are atypical for the overall use of the stored procedure, a less than ideal execution plan will be cached for all subsequent calls.

Simply dropping and recompiling the stored procedure does not seem to affect the cached execution plan. Updating statistics on the tables used in the stored procedure will cause the execution plan to be regenerated on the next call of the stored procedure. However, if the same or similar atypical parameters are used on the first execution of the stored procedure, an equally sub-optimal execution plan will be cached.

You can turn off parameter sniffing. This is accomplished by assigning the input parameter values to local variables inside the stored procedure and then using the local variables within the stored procedure. When the execution plan is created, SQL Server will look at the table statistics to optimize the query for the "average" use. It does this by looking at the tables used in the query and analyzing row counts, etc. to find a reasonable plan that will likely suit a majority of situations.

My stored procedure was bringing back multiple resultsets to be used to create a hierarchical structure in code. It works essentially like the following:

CREATE PROCEDURE [dbo].[usp_Order_GetOrderDetails]
(
   @StartOrderId INT,
   @EndOrderId INT
)
AS
BEGIN

   SELECT *
   FROM Order
   WHERE OrderId BETWEEN @StartOrderId AND @EndOrderId
 
   SELECT *
   FROM OrderLineItem
   WHERE OrderId BETWEEN @StartOrderId AND @EndOrderId
END

I was testing the stored procedure for full day using the same ID for @StartOrderId and @EndOrderId. Since the intended use of this stored procedure is almost always @EndOrderId = @StartOrderId + 1000, this makes a big difference when calculating the estimate number of rows returned. I forced SQL Server to assume that my execution plan should be based on an ID range of 1 instead of 1000. Turning off parameter sniffing lessens these effects.

To turn off parameter sniffing, it would look like this:

CREATE PROCEDURE [dbo].[usp_Order_GetOrderDetails]
(
   @StartOrderId INT,
   @EndOrderId INT
)
AS
BEGIN
   DECLARE @Start INT
   DECLARE @End INT
   SET @Start = @StartOrderId
   SET @End = @EndOrderId
 

   SELECT *
   FROM Order
   WHERE OrderId BETWEEN @Start AND @End
 
   SELECT *
   FROM OrderLineItem
   WHERE OrderId BETWEEN @Start AND @End
END

This immediately improved the performance of my stored procedure. The time to complete reduced from ~2 minutes to ~2 seconds for my typical 1000 ID range (I know 2 seconds is a lot, but these tables have millions and millions of rows). But only one piece of code in the application calls this stored procedure, and 99 out of 100 times it will have a range of 1000 IDs. Why would I want SQL Server to guess how many Orders I will typically bring back when I know the exact number?

I should have the optimal execution plan if I update statistics on Order and OrderLineItem, and then call usp_Order_GetOrderDetails 1, 1000 after I compile this stored procedure. This sounds like a lot of work to me, and I did not notice any performance boost by doing this. I chose to leave parameter sniffing off.

The only drawbacks to turning off parameter sniffing is the weird looking SQL and the inevitable questions during code review about the crazy input parameter to variable mapping. But when you school the doubters on the causes and effects of parameter sniffing, it will put another notch in your guru stick.

From what I have read, this was not a new feature in SQL 2005. I can't, however, find any mention of it in SQL 2000 books online, and this feature never showed its face in SQL 2000.

Saturday, June 21, 2008 9:24:02 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]   Database | SQL  | 
# Wednesday, June 18, 2008

Juval Löwy mentioned the Microsoft Service Trace Viewer in a webcast today. If you ever wondered exactly what WCF does under all of those covers, check this out.

First things first. Enable tracing on the client and host applications using the WCF Configuration Editor. Enable the verbose trace level and check all of the listener settings. This will add all of the necessary <system.diagnostics> settings in your config file. The next time you start each of the applications, a .svclog file will be created that will be used by the Service Trace Viewer.

Start your host, start your client, run through the test cases that you want to analyze in the viewer. After your test run is complete, open the viewer, located at C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\SvcTraceViewer.exe. "Open" the host.svclog file, and then "Add" the client.svclog file. Both "Open" and "Add" are menu items under "File".

Start on the Activity tab, look through the host and client activities that occurred. Everything from ServiceHost construction through ServiceHost closing shows up. This is very cool, especially when analyzing the differences between different security, session, and reliability settings.

When you are done looking through the activities, check out the Graph tab. Here you can look at the interactions between the client and host, as well as looking at the details of each activity (at the top right). At the bottom right, you will also notice the formatted and xml details of this activity.

This is a very cool tool for both debugging and training. Below is my lame test projects, if you want to skip past the configuration and check out the tool. My .svclog files are located in the Client and Host folders.

SvtTest.zip (190.32 KB)

Enjoy! Thanks to Juval for the direction.

Wednesday, June 18, 2008 9:23:30 PM (Eastern Standard Time, UTC-05:00)  #    Comments [5]   .NET Framework | C# | Dev Tools | Visual Studio | WCF  | 

I couldn't take the X-Files-esque output window anymore. Here are my spinoffs of the ZenBurn (recently posted as ScottGu's) theme.

VSSettings1.zip (118.09 KB)

Wednesday, June 18, 2008 8:44:39 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3]   Visual Studio  | 
# Thursday, May 29, 2008

I have been using ScottGu's Visual Studio 2008 theme for the last few weeks and love it. You can see it here and download it here.

Thursday, May 29, 2008 9:21:53 PM (Eastern Standard Time, UTC-05:00)  #    Comments [5]   Dev Tools | Visual Studio  | 
# Wednesday, March 26, 2008

I was looking for guidance on this topic, and came up with nothing. I'm sure people are doing this, but can't find any info. For anyone looking like I was, here's how to do it.

It's much simpler than I imagined, thanks to WCF. You can programmatically create your endpoint, binding, and channel inside your service. This would require that the address be hard-coded and require a recompile to change the address or binding. As long as your host's app.config or web.config has a client endpoint specifying the contract, you don't have to go through all that work. Your service is simply a client of another service, so your code looks just like that of a client of your service. Furthermore, changing the address or binding is as simple as changing config file values.

Service code:

    1 using System;

    2 using System.ServiceModel;

    3 using DataContracts;

    4 namespace ServiceImplementation

    5 {

    6     [ServiceContract]

    7     public interface IEmailService

    8     {

    9         [OperationContract]

   10         void Send(DataContracts.MailMessage msg);

   11     }

   12 

   13     public class EmailService : IEmailService

   14     {

   15         [OperationBehavior]

   16         public void Send(DataContracts.MailMessage msg)

   17         {

   18             // Open client proxy for legacy web service

   19             using (LegacyEmailServiceClient proxy =

   20                 new LegacyEmailServiceClient())

   21             {

   22                 proxy.SendEmail(msg.To,

   23                     msg.CC,

   24                     msg.Bcc,

   25                     msg.Body,

   26                     msg.Attachments);

   27             }

   28         }

   29     }

   30 }

   31 



Host's app.config:

    1 <?xml version="1.0" encoding="utf-8"?>

    2 <configuration>

    3   <system.serviceModel>

    4     <bindings>

    5       <basicHttpBinding>

    6         <binding name="BasicHttpBinding_Common">

    7           <security mode="None"/>

    8         </binding>

    9       </basicHttpBinding>

   10       <netTcpBinding>

   11         <binding name="NetTcpBinding_Common">

   12           <security mode="None"/>

   13         </binding>

   14       </netTcpBinding>

   15     </bindings>

   16     <client>

   17       <endpoint address="http://www.gotjeep.net/legacy/email.asmx"

   18           binding="basicHttpBinding"

   19                 bindingConfiguration="BasicHttpBinding_Common"

   20           contract="LegacyEmailServiceClient"

   21                 name="LegacyEmailServiceClient" />

   22     </client>

   23     <services>

   24       <service name="ServiceImplementation.EmailService"

   25               behaviorConfiguration="returnFaults">

   26         <host>

   27           <baseAddresses>

   28             <add baseAddress="http://localhost:8080/EmailService" />

   29             <add baseAddress="net.tcp://localhost:8088/EmailService" />

   30           </baseAddresses>

   31         </host>

   32         <endpoint name="NetTcpBinding_EmailService"

   33                   binding="netTcpBinding"

   34                   bindingConfiguration="NetTcpBinding_Common"

   35                   contract="ServiceImplementation.IEmailService"/>

   36         <endpoint name="BasicHttpBinding_EmailService"

   37                   binding="basicHttpBinding"

   38                   bindingConfiguration="BasicHttpBinding_Common"

   39                   contract="ServiceImplementation.IEmailService"/>

   40       </service>

   41     </services>

   42     <behaviors>

   43       <serviceBehaviors>

   44         <behavior name="returnFaults" >

   45           <serviceMetadata httpGetEnabled="true" />

   46         </behavior>

   47       </serviceBehaviors>

   48     </behaviors>

   49   </system.serviceModel>

   50 </configuration>

Wednesday, March 26, 2008 9:08:46 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3]   .NET Framework | C# | WCF  | 
# Tuesday, March 25, 2008

If you haven't heard me praise Juval Löwy's book Programming WCF Services or Michele Leroux Bustamante's book Learning WCF: A Hands-on Guide yet... these books are the best WCF books available. Every question I have had has been answered by these two books. In fact, most of the forum and newsgroup resolutions out there come from one or both of these books. If you haven't already, check out their IDesign Code Library and and the IDesign WCF Coding Standard at www.IDesign.net.

OK, problem and resolution of the day... how do I generate a proxy file with the same collection class as my service implementation. My service uses List<T>. WCF converts this to be a more interoperable array of T. When you generate the proxy, it is generated with T[]. To be able to enjoy the same collection features as the service, you only need a few more parameters on svcutil.

    7     [ServiceContract]

    8     public interface IEmailService

    9     {

   10         [OperationContract]

   11         string MyOperation1(string myValue);

   12 

   13         [OperationContract]

   14         List<String> MyOperation2(string myValue);

   15     }

Example 1: Generate proxy with T[]

svcutil http://localhost:8080/EmailService /out:EmailServiceProxy.cs /noconfig

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEmailService/MyOperation2", ReplyAction="http://tempuri.org/IEmailService/MyOperation2Response")]
string[] MyOperation2(string myValue);

Example 2: Generate proxy with List<T>

svcutil http://localhost:8080/EmailService /out:EmailServiceProxy.cs /noconfig /ct:System.Collections.Generic.List`1

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IEmailService/MyOperation2", ReplyAction="http://tempuri.org/IEmailService/MyOperation2Response")]
System.Collections.Generic.
List<string> MyOperation2(string myValue);

Tuesday, March 25, 2008 9:22:22 PM (Eastern Standard Time, UTC-05:00)  #    Comments [9]   .NET Framework | WCF | C#  | 
# Monday, March 24, 2008

Before you try running a Console Application or Windows Service application that hosts a WCF service with basicHttpBinding or wsHttpBinding, see this MSDN article about "Configuring HTTP and HTTPS". If you are WAS-hosted or Web App-hosted, the urlacl entries are made on your behalf.

You can view the current entries with "netsh http show urlacl". To make the changes, you'll need to "Run as Administrator" when going into your Command Prompt.

I decided to use the following command:

netsh http add urlacl url=http://+:8080/ user=\Everyone

You should adjust the ports and/or path as necessary for your situation:

netsh http add urlacl url=http://+:8080/MyConsoleAppHostedService user=DOMAIN\user

netsh http add urlacl url=http://+:8091/MyWindowsServiceHostedService user=\SYSTEM

Monday, March 24, 2008 8:03:15 PM (Eastern Standard Time, UTC-05:00)  #    Comments [2]   .NET Framework | WCF  | 
# Saturday, March 22, 2008

WCF is seamless, powerful, and (YES) interoperable. Here is a quick walkthrough detailing steps to call your legacy PHP web services from a WCF client. All of the binding types and security options are, of course, not available. But for those of you following the old "security through obscurity" model, this will work fine.

The procedure is just as simple as a WCF-WCF call:
  1. Create client proxy
  2. Add client endpoint to your client config file
  3. Write your proxy-consuming client code

Create the client proxy:

Nusoap provides a similar UI when navigating to your PHP web service to that provided by ASMX services. You can view the WSDL, and copy the URL for svcutil.exe.

From the Visual Studio 2005 Command Prompt, type:

svcutil <url> /out:<name>Proxy.cs /noconfig
svcutil http://gotjeep.net/services/ApproachAngleService.php?wsdl /out:ApproachAngleServiceProxy.cs /noconfig

This generates a file named ApproachAngleServiceProxy.cs.

    1 //------------------------------------------------------------------------------

    2 // <auto-generated>

    3 //    This code was generated by a tool.

    4 //    Runtime Version:2.0.50727.1433

    5 //

    6 //    Changes to this file may cause incorrect behavior and will be lost if

    7 //    the code is regenerated.

    8 // </auto-generated>

    9 //------------------------------------------------------------------------------

   10 

   11 

   12 

   13 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]

   14 [System.ServiceModel.ServiceContractAttribute(Namespace="http://www.gotjeep.net/tech", ConfigurationName="GotJeepApproachAngleCalculatorPortType")]

   15 public interface GotJeepApproachAngleCalculatorPortType

   16 {

   17 

   18     [System.ServiceModel.OperationContractAttribute(Action="http://www.gotjeep.net/services/approachAngleService.php/CalculateApproachAngle", ReplyAction="*")]

   19     [System.ServiceModel.XmlSerializerFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Rpc, Use=System.ServiceModel.OperationFormatUse.Encoded)]

   20     [return: System.ServiceModel.MessageParameterAttribute(Name="return")]

   21     decimal CalculateApproachAngle(decimal height, decimal diameter, decimal distance);

   22 }

   23 

   24 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]

   25 public interface GotJeepApproachAngleCalculatorPortTypeChannel : GotJeepApproachAngleCalculatorPortType, System.ServiceModel.IClientChannel

   26 {

   27 }

   28 

   29 [System.Diagnostics.DebuggerStepThroughAttribute()]

   30 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]

   31 public partial class GotJeepApproachAngleCalculatorPortTypeClient : System.ServiceModel.ClientBase<GotJeepApproachAngleCalculatorPortType>, GotJeepApproachAngleCalculatorPortType

   32 {

   33 

   34     public GotJeepApproachAngleCalculatorPortTypeClient()

   35     {

   36     }

   37 

   38     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName) :

   39             base(endpointConfigurationName)

   40     {

   41     }

   42 

   43     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName, string remoteAddress) :

   44             base(endpointConfigurationName, remoteAddress)

   45     {

   46     }

   47 

   48     public GotJeepApproachAngleCalculatorPortTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :

   49             base(endpointConfigurationName, remoteAddress)

   50     {

   51     }

   52 

   53     public GotJeepApproachAngleCalculatorPortTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :

   54             base(binding, remoteAddress)

   55     {

   56     }

   57 

   58     public decimal CalculateApproachAngle(decimal height, decimal diameter, decimal distance)

   59     {

   60         return base.Channel.CalculateApproachAngle(height, diameter, distance);

   61     }

   62 }

 

Add client endpoint to your config file:

You have the option of letting svcutil create your config file or using "Generate Service Reference", but I prefer to avoid the extra 20+ lines of config file defaults included by svcutil. It's not hard to write it yourself, and it ensures a much more readable config file.

    1 <?xml version="1.0" encoding="utf-8"?>

    2 <configuration>

    3     <system.serviceModel>

    4         <bindings>

    5             <basicHttpBinding>

    6               <binding name="GotJeepApproachAngleCalculatorBinding">

    7                 <security mode="None"/>

    8               </binding>

    9             </basicHttpBinding>

   10         </bindings>

   11         <client>

   12             <endpoint address="http://www.gotjeep.net/services/approachAngleService.php"

   13                 binding="basicHttpBinding"

   14                 bindingConfiguration="GotJeepApproachAngleCalculatorBinding"

   15                 contract="GotJeepApproachAngleCalculatorPortType"

   16                 name="GotJeepApproachAngleCalculatorPort" />

   17         </client>

   18     </system.serviceModel>

   19 </configuration>

 

Write the client code:

    1 using System;

    2 

    3 namespace Client

    4 {

    5     class Program

    6     {

    7         static void Main(string[] args)

    8         {

    9             using (GotJeepApproachAngleCalculatorPortTypeClient proxy =

   10                 new GotJeepApproachAngleCalculatorPortTypeClient())

   11             {

   12                 decimal result = proxy.CalculateApproachAngle(25.6m, 33.2m, 17.75m);

   13                 Console.WriteLine("decimal result = proxy.CalculateApproachAngle(25.6m, 33.2m, 17.75m);");

   14                 Console.WriteLine("result = " + result.ToString("0.00"));

   15             }

   16         }

   17     }

   18 }

 

Check it out:

A request-reply call between WCF and a Nusoap PHP web service.

Saturday, March 22, 2008 9:25:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments [5]   .NET Framework | C# | WCF  | 
Copyright © 2010 Scott Klueppel. All rights reserved.