<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4800634963970790114</id><updated>2011-10-06T12:07:55.912-04:00</updated><category term='LINQ'/><category term='quality'/><category term='performance'/><category term='testing'/><category term='WCF'/><category term='photography'/><category term='security'/><category term='Entity Framework'/><category term='ASP.NET'/><category term='presentations'/><category term='ADO.NET'/><title type='text'>Too Many Layers of Abstraction</title><subtitle type='html'>This is all making a kind of sense that's... not.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-5205463698713983945</id><published>2009-03-03T15:37:00.002-05:00</published><updated>2009-04-08T16:39:08.443-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><title type='text'>ASP.NET Security Presentation</title><content type='html'>&lt;p&gt;I'm presenting April 8 at the &lt;a href="http://www.trinug.org/"&gt;TriNUG&lt;/a&gt; in Raleigh/Durham, NC. I'll be talking about web security and showing sample code. &lt;a href="http://dianewilson.us/linq/presentations/WebSecurity.zip"&gt;Presentation and sample code can be found here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-5205463698713983945?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/5205463698713983945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=5205463698713983945' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5205463698713983945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5205463698713983945'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/03/aspnet-security-presentation.html' title='ASP.NET Security Presentation'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-1002288425444093979</id><published>2009-01-29T10:22:00.003-05:00</published><updated>2009-01-29T10:26:31.823-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Entity Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ to SQL vs. LINQ to Entity Framework</title><content type='html'>&lt;p&gt;No, this isn't a cage match. Sorry to those who expected otherwise.&lt;/p&gt;&lt;p&gt;What I do want to point out is that the programming models are different, and differ in ways that are going to make some people think that certain features are missing from one tool or the other. If you're one of those people who thinks that LINQ to SQL has a performance problem because of lazy loading, or that LINQ to Entity Framework doesn't give you a way to turn off change tracking for query-only usage, then I'm talking to &lt;strong&gt;&lt;em&gt;you&lt;/em&gt;&lt;/strong&gt;, friend!&lt;/p&gt;&lt;p&gt;For instance, let's look at that change tracking issue. Both LINQ to SQL and LINQ to EF will track changes to entities so that you can change data in an object and save the data simply by submitting changes through the DataContext or ObjectContext. But for query-only operations, this change tracking is unnecessary, and you can turn it off. Here's how you do it in LINQ to SQL:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;Customer&amp;gt; GetCustomers()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (NorthwindData dc = &lt;span class="kwrd"&gt;new&lt;/span&gt; NorthwindData())&lt;br /&gt;    {&lt;br /&gt;        dc.ObjectTrackingEnabled = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; (from c &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.Customers select c).ToList();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;And here's how you do it in LINQ to Entity Framework:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;Customers&amp;gt; GetCustomers()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (NorthwindEntities ne = &lt;span class="kwrd"&gt;new&lt;/span&gt; NorthwindEntities())&lt;br /&gt;    {&lt;br /&gt;        ne.Customers.MergeOption = MergeOption.NoTracking;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; (from c &lt;span class="kwrd"&gt;in&lt;/span&gt; ne.Customers select c).ToList();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;Note the big difference here. In LINQ to SQL, you turn off tracking in the DataContext. In LINQ to EF, you turn off tracking in the entity collection. If you're looking in the wrong place, you'll miss it.&lt;/p&gt;&lt;p&gt;The same pattern holds true with eager loading and lazy loading. In LINQ to SQL, it's controlled with a DataLoadOptions object attached to the DataContext. In LINQ to EF, it's set at the entity level, either in the query (eager loading) or in processing the results (lazy loading). &lt;/p&gt;&lt;p&gt;I'll cover eager loading and lazy loading in a follow-up post, because there's a nasty surprise waiting in LINQ to SQL eager loading.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-1002288425444093979?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/1002288425444093979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=1002288425444093979' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/1002288425444093979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/1002288425444093979'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/01/linq-to-sql-vs-linq-to-entity-framework.html' title='LINQ to SQL vs. LINQ to Entity Framework'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-7437864016224765146</id><published>2009-01-25T15:58:00.002-05:00</published><updated>2009-02-17T14:42:08.735-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Entity Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Entity Framework and LINQ to SQL Performance</title><content type='html'>&lt;p&gt;Updated: Modified embedded SQL queries to use parameters where appropriate. Results updated.&lt;/p&gt;  &lt;p&gt;I've been playing with Entity Framework recently, and noticed that it seemed to be much slower than LINQ to SQL. I ran some tests, and sure enough, I was right. The numbers are interesting:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://dianewilson.us/linq/presentations/performance.chart.gif" /&gt; &lt;/p&gt;  &lt;p&gt;The code is available &lt;a href="http://dianewilson.us/linq/presentations/Performance.Tests.zip"&gt;here&lt;/a&gt; if you want to run these tests yourself.&lt;/p&gt;  &lt;h4&gt;Methodology&lt;/h4&gt;  &lt;p&gt;The structure of the test was to set up a static method to return data from the Customers table of Northwind, suitable for binding to an ObjectDataSource in ASP.NET. I ran two sets of tests, one to return six columns from all rows, and one to return the same six columns from a single row. Each set contained the following variations:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;DataReader, to provide baseline performance to compare against other technologies. &lt;/li&gt;    &lt;li&gt;DataTable, using classic ADO.NET tools (DataAdapter running a command to fill a table). &lt;/li&gt;    &lt;li&gt;LINQ to SQL, using a compiled query, and with object tracking turned off, to maximize performance. The results list was projected directly from the query. &lt;/li&gt;    &lt;li&gt;LINQ to Entity Framework, using a compiled query to maximize performance. As with LINQ to SQL, the results list was projected directly from the query. &lt;/li&gt;    &lt;li&gt;Entity SQL, as an alternative to LINQ, querying the Entity Framework. The code structure for Entity SQL uses a reader, similar to using a DataReader with T-SQL. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For both LINQ to SQL and Entity Framework, I used the visual designer tools to include only the Customers table in the model.&lt;/p&gt;  &lt;p&gt;The test measured elapsed time and total processor time. The difference could be assumed to include time used by SQL Server, as well as any other out-of-process time. I ran the tests on a Dell Latitude E6500 with Vista Ultimate, SQL Server 2008, an Intel Core 2 Duo P9500 (2.5 GHz), 4GB RAM, and 7200 RPM disk. The system was idle except for tests; test runs were fairly consistent in timings, as measured by standard deviations over a set of 10 test runs.&lt;/p&gt;  &lt;p&gt;The test program ran each query once to ensure that all code was loaded and JITed, and all access plans and data were cached, so that startup time was excluded for each scenario. The program then ran 10,000 queries and collected aggregate time and working set information. For each scenario, the test program was run once, then run 10 times to record timing data.&lt;/p&gt;  &lt;h4&gt;Results&lt;/h4&gt;  &lt;p&gt;Keep in mind that the test was designed to measure only the code execution for queries. There is no business logic, and the test design ensured that start-up costs were excluded from test results.&lt;/p&gt;  &lt;p&gt;As expected, using a DataReader with raw T-SQL is the best performer, and the technology of choice for extremely large data volumes and for applications where performance is the only thing that matters. The DataReader used .40 milliseconds (elapsed) to retrieve 92 rows and store the data in a list, and only .15 milliseconds for a single row.&lt;/p&gt;  &lt;p&gt;The DataTable with classic ADO.NET performed almost as well, using .58 milliseconds (elapsed) for 92 rows and .18 milliseconds for a single row. In the chart above, the DataReader is used as a baseline for comparison, so the relative cost of using a DataTable and DataAdapter was 1.4 for 92 rows, and 1.2 for a single row. That's not a lot of overhead in exchange for using a standardized structure that includes metadata on names and data types. Memory usage was virtually identical to memory usage for the DataReader.&lt;/p&gt;  &lt;p&gt;LINQ to SQL also performed very well, using .63 milliseconds (elapsed) for 92 rows and .36 milliseconds for a single row. The performance ratio compared to the DataReader is 1.6 for 92 rows and 2.3 for a single row. Compared to the DataTable, the performance ratio (not charted) was 1.2 for 92 rows and 1.9 for a single row. LINQ to SQL used 40 MB additional memory, based on the final working set size at the end of each run. &lt;/p&gt;  &lt;p&gt;That's very decent performance, considering the&amp;#160; additional overhead, although Rico Mariani of Microsoft got &lt;a href="http://blogs.msdn.com/ricom/archive/2007/07/05/dlinq-linq-to-sql-performance-part-4.aspx"&gt;even better&lt;/a&gt; numbers (and I'd love to know how to get closer to those results). In my tests, all queries established new connection objects (or data contexts) for each query, but I can't tell if Rico did the same in his performance tests. This may account for the difference in performance.&lt;/p&gt;  &lt;p&gt;With Entity Framework, I found significant additional performance costs. LINQ to EF used 2.73 milliseconds (elapsed) to retrieve 92 rows, and 2.43 milliseconds for a single row. For 92 rows, that's a performance ratio of 6.8 compared to the DataReader, 4.7 compared to the DataTable, and 4.4 compared to LINQ to SQL (the latter two are not charted above). For a single row, LINQ to EF used 2.43 millisecond (elapsed), with performance ratios of 16.0 compared to the DataReader, 13.2 compared to the DataTable, and 6.8 compared to LINQ to SQL. Memory usage for LINQ to EF was about 130 MB more than for the DataReader.&lt;/p&gt;  &lt;p&gt;Entity SQL queries to EF performed about the same as LINQ to EF, with 2.78 milliseconds (elapsed) for 92 rows and 2.32 milliseconds for a single row. Memory usage was similar to LINQ to EF.&lt;/p&gt;  &lt;h4&gt;Conclusions&lt;/h4&gt;  &lt;p&gt;Some of the conclusions are obvious. If performance is paramount, go with a DataReader! Entity Framework uses two layers of object mapping (compared to a single layer in LINQ to SQL), and the additional mapping has performance costs. At least in EF version 1, application designers should choose Entity Framework only if the modeling and ORM mapping capabilities can justify that cost.&lt;/p&gt;  &lt;p&gt;In between those extremes, the real surprise is that LINQ to SQL can perform so well. (The caveat is that tuning LINQ to SQL is not always straight-forward.) The advantage that LINQ (including LINQ to EF) offers is in code quality, resulting from two key improvements over classic ADO.NET:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Names and data types are strongly enforced from top to bottom of your application. Very specifically, that means all the way down to the tables in the database. LINQ uses .NET types, further simplifying the developer's life. &lt;/li&gt;    &lt;li&gt;DataTables and DataSets bring the relational data model rather intrusively into the code. To process data in a DataTable, you must adapt your code to the DataTable structure, including DataRows, DataColumns, and (with DataSets and multiple tables) DataRelationships. By contrast, LINQ is a first-class language component in .NET, with object-relational mapping inherent in the LINQ data providers and models. Processing data with LINQ &lt;em&gt;feels&lt;/em&gt; like processing object collections, because that's exactly what you're doing. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So for now, LINQ to SQL is a winner! As Entity Framework version 2 takes shape, it will be time to re-evaluate.&lt;/p&gt;  &lt;p&gt;Edited to fix math errors (blush). These affect timings only, but since the chart is based on ratios, those numbers are still correct.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-7437864016224765146?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/7437864016224765146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=7437864016224765146' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7437864016224765146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7437864016224765146'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/01/entity-framework-and-linq-to-sql.html' title='Entity Framework and LINQ to SQL Performance'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-7030745670942333778</id><published>2009-01-18T16:49:00.004-05:00</published><updated>2009-01-29T09:56:32.110-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='presentations'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Triad SQL Server Group</title><content type='html'>&lt;p&gt;I'll be speaking at the &lt;a href="http://www.triadsql.com/"&gt;Triad SQL Server Group&lt;/a&gt; on Tuesday, February 17, at 6:00 pm. The topic is "The LINQ Revolution":&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Microsoft's inclusion of query capabilities as a first-class language component in .NET, along with two object-relational mapping (ORM) solutions in LINQ to SQL and the Entity Framework, will change the ways that you develop database applications. This will be an open discussion, where you choose the topics of greatest interest, including anything from LINQ syntax and code generation to ORM, domain-driven design, n-tiered design issues as they related to LINQ and ORM, the changing role of stored procedures with ORM, and entity-relationship modeling now that E-R models can be represented directly in code.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Presentation materials and sample code are &lt;a href="http://dianewilson.us/linq/presentations/Triad.SQL.Group.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;If you're in the area, I hope to see you there!&lt;/p&gt;&lt;p&gt;ETA: Date changed again. This time we won't let it snow that day!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-7030745670942333778?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/7030745670942333778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=7030745670942333778' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7030745670942333778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7030745670942333778'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/01/triad-sql-server-group.html' title='Triad SQL Server Group'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-8028832186927199721</id><published>2009-01-07T13:08:00.003-05:00</published><updated>2009-01-07T15:00:40.630-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ of the Day</title><content type='html'>&lt;p&gt;One of the delights of LINQ to SQL is that it's an extension of LINQ to objects, but it doesn't implement everything that LINQ to objects implements. The constraint on LINQ to SQL is that the expression must be translatable into T-SQL. If you write LINQ expressions that don't translate to T-SQL, your code will compile cleanly, but will fail when LINQ is ready to do the translation. (The exception and call stack can best be described as &amp;quot;educational.&amp;quot;) Let's look at an example that fixes the problem.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;MultiplierDefinition&amp;gt; GetAllMultipliers()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (FSP dc = FSP.DC())&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; GetMultipliers(dc)&lt;br /&gt;            .AsEnumerable()&lt;br /&gt;            .OrderBy(m =&amp;gt; m, &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierDescComparer&amp;lt;MultiplierDefinition&amp;gt;())&lt;br /&gt;            .ToList();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Before tearing into this, let's take a quick look at GetMultpliers, which is a &lt;a href="http://toomanylayers.blogspot.com/2008/12/linq-of-day_16.html"&gt;compiled LINQ-to-SQL query&lt;/a&gt;. There's nothing strange about it; I write stuff like this routinely. The thing to note is that it returns an IQueryable&amp;lt;MultiplierDefinition&amp;gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Func&amp;lt;FSP, IQueryable&amp;lt;MultiplierDefinition&amp;gt;&amp;gt; GetMultipliers = &lt;br /&gt;    CompiledQuery.Compile(&lt;br /&gt;    (FSP dc) =&amp;gt; from m &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.Pm_Multipliers&lt;br /&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; m.RecordDeleted != &lt;span class="kwrd"&gt;true&lt;/span&gt;&lt;br /&gt;                select &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierDefinition&lt;br /&gt;                {&lt;br /&gt;                    MultiplierID = m.MultiplierID,&lt;br /&gt;                    Description = m.Description,&lt;br /&gt;                    DiscountPercent = m.DiscountPercent,&lt;br /&gt;                    CreatedByUser = m.CreatedByUser,&lt;br /&gt;                    DateCreated = m.DateCreated,&lt;br /&gt;                    ModifiedByUser = m.ModifiedByUser,&lt;br /&gt;                    DateModified = m.DateModified,&lt;br /&gt;                    RecordDeleted = m.RecordDeleted&lt;br /&gt;                });&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;So my method GetAllMultipliers() starts by getting a DataContext, and calling a method to get a LINQ-to-SQL expression tree. But the next thing I need to do is sort the data, using a custom sorting algorithm contained in an IComparer&amp;lt;T&amp;gt; object called MultiplierDescComparer&amp;lt;MultiplierDefinition&amp;gt;. There's no way that T-SQL can sort using a C# object! Once the sorting is done, I simply return a generic List&amp;lt;MultiplierDefinition&amp;gt; to my client code.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;There are two secrets to making this work. One is that you can add LINQ expressions to a compiled query; they'll be added to the expression tree before the query runs. The second secret, and the important one, is that innocuous little method, .AsEnumerable(). Hey! IQueryable&amp;lt;T&amp;gt; implements IEnumerable&amp;lt;T&amp;gt;, so we're already enumerable. Why do we have to this explicit... Conversion? Reminder? Expositional countersinking? No-op?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;It's a conversion, and here's what it means. Everything before .AsEnumerable() will translate to T-SQL and run in the database. Everything after .AsEnumerable() is a LINQ to objects expression, and will run on the data returned from the database. (That's always a core difference between IQueryable&amp;lt;T&amp;gt; and IEnumerable&amp;lt;T&amp;gt;, and that's why you don't want to store a LINQ-to-SQL query as an IEnumerable&amp;lt;T&amp;gt;, unless you want to force any subsequent LINQ expressions to be run in memory.)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;None of this forces immediate execution; it's all still deferred execution, right up to the .ToList() method. Evaluating and understanding the entire code and execution path is a bit convoluted, but definitely enlightening. .AsEnumerable() is always useful when you want to use LINQ that doesn't have a counterpart in T-SQL (for example, .SkipWhile() and .TakeWhile()).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-8028832186927199721?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/8028832186927199721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=8028832186927199721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/8028832186927199721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/8028832186927199721'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/01/linq-of-day.html' title='LINQ of the Day'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-1053386765808674019</id><published>2009-01-01T14:56:00.001-05:00</published><updated>2009-01-01T14:56:48.598-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='photography'/><title type='text'>Happy New Year</title><content type='html'>&lt;p&gt;A small reminder that even in a rough year, some things remain beautiful.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.firelily.com/photos/bumblebee.small.jpg" /&gt;&lt;/p&gt;  &lt;p&gt;Also noting that my job has been extended through almost the end of January. So that's a good start. &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-1053386765808674019?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/1053386765808674019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=1053386765808674019' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/1053386765808674019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/1053386765808674019'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2009/01/happy-new-year.html' title='Happy New Year'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-4006604536725474103</id><published>2008-12-16T11:18:00.001-05:00</published><updated>2008-12-16T11:18:31.459-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ of the Day</title><content type='html'>&lt;p&gt;Today's LINQ covers a several points: Providing an object data source, suitable for binding. Making a query reusable, and pre-compiling it for best performance. Selecting useful objects.&lt;/p&gt;  &lt;p&gt;Here's the code:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;IndependentRep&amp;gt; IndependentRepList()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (FSP dc = FSP.DC())&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; GetIndependentRepQuery(dc).ToList();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Func&amp;lt;FSP, IQueryable&amp;lt;IndependentRep&amp;gt;&amp;gt;&lt;br /&gt;    GetIndependentRepQuery = CompiledQuery.Compile(&lt;br /&gt;    (FSP dc) =&amp;gt; from u &lt;span class="kwrd"&gt;in&lt;/span&gt; dc.Pm_Logins&lt;br /&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; (!u.RecordDeleted) &amp;amp;&amp;amp;&lt;br /&gt;                      (u.LoginType == Util.c_Login_IndependentSalesRep)&lt;br /&gt;                select &lt;span class="kwrd"&gt;new&lt;/span&gt; IndependentRep&lt;br /&gt;                {&lt;br /&gt;                    UserName = u.UserName,&lt;br /&gt;                    RepContact = &lt;span class="kwrd"&gt;new&lt;/span&gt; Contact&lt;br /&gt;                    {&lt;br /&gt;                        FirstName = u.FirstName,&lt;br /&gt;                        LastName = u.LastName,&lt;br /&gt;                        OfficePhone = u.OfficePhone,&lt;br /&gt;                        MobilePhone = u.MobilePhone,&lt;br /&gt;                        Email = u.Email,&lt;br /&gt;                        CompanyName = u.CompanyName&lt;br /&gt;                    },&lt;br /&gt;                    Status = u.Status&lt;br /&gt;                });&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Providing an Object Data Source&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;You'll notice that there are two static functions here, a public static function that calls a private static function. The public function has no arguments, so it's ideal for binding with an object data source. It could pull parameters for session data or the application cache, if the scope of the data needed to be constrained based on context, but we're not doing that here. All we do is grab a data context and call the private function, then return the results as a list.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Reusable Pre-Compiled Queries&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This might look a bit intimidating at first, but it's well worth the effort to learn and use. The CompiledQuery.Compile method provides a way to compile a LINQ query and cache the expression tree, so that it can be re-used without the overhead of re-evaluating the query each time. The query is compiled on first use, and (as far as I know) has the lifetime of the AppDomain.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The Compile method is overloaded to allow you to pass zero to three arguments to the query. We're not passing any arguments to the query itself in this case, but if we were, they would come between the first and last arguments listed in &amp;quot;Func&amp;quot;. &amp;quot;Func&amp;quot; is a generic delegate template, so at this point we're specifying types. The first type is always the data context, and the last argument is always the return type of the query. By leaving the return type as IQueryable&amp;lt;T&amp;gt;, callers can always add more LINQ methods to further refine the query before it goes to the database. (And remember, we're doing the ultimate in deferred query execution here; the query never gets executed inside this function.)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;CompiledQuery.Compile actually takes only one argument, and that's a lambda expression that defines the query itself. The arguments to the lambda expression are all of the types listed in &amp;quot;Func&amp;quot; except the return type. In defining the arguments for the lambda expression, we're providing both types and parameter names, and the parameter names are used inside the query. To the right of the lambda operator (&amp;quot;=&amp;gt;&amp;quot;), we have a normal LINQ query, with the exception that you must return a named class type that matches the return type in &amp;quot;Func&amp;quot;. That class can be either an entity known to your data context, or it can be a class defined in your application.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Selecting Useful Objects&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Look at the select clause in the query. Select always returns one object, in this case a new instance of type IndependentRep. IndependentRep is an application-defined class with three members:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; IndependentRep&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; UserName&lt;br /&gt;    { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Contact RepContact&lt;br /&gt;    { get; set; }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Status&lt;br /&gt;    { get; set; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As we initialize the object in the select clause, we can assign values to UserName and Status directly. We can also create a new instance of a Contact class, and populate that as well with data from the query. In this case, we're generating a simple class for use in databinding, but you could also have the select clause generate a pre-populated business entity, a class with its own business rules and perhaps its own persistence and update methods.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Putting LINQ into production means being comfortable with selecting from the many features of LINQ, and combining these into coherent and useful units of work. This is a real-life example.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-4006604536725474103?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/4006604536725474103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=4006604536725474103' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/4006604536725474103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/4006604536725474103'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/12/linq-of-day_16.html' title='LINQ of the Day'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-5734649779482471618</id><published>2008-12-12T13:46:00.003-05:00</published><updated>2008-12-12T14:05:45.355-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ of the Day</title><content type='html'>&lt;p&gt;Here's an interesting problem. A table has multiple foreign key references to another table. Each foreign key reference has a different meaning, so they're unique. I need a list of the items referenced, with context information so that I know the usage of the reference. If Table One references Table Two twice in the same row, that's two distinct usages, and should generate two separate records for output.&lt;/p&gt;  &lt;p&gt;That's just enough difference to make life interesting, because the output needs information from both tables as well as a constant identifying context and usage. In T-SQL, this is a fairly simple set of four joins, combined with a union so we get all our output in one result set. &lt;/p&gt;  &lt;p&gt;Here's the LINQ to do this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;IQueryable&amp;lt;MultiplierCustomer&amp;gt; StdCustomers =&lt;br /&gt;    dc.Pm_VisualCustMultipliers&lt;br /&gt;        .Where(vcm =&amp;gt; vcm.RecordDeleted == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;        .Where(vc =&amp;gt; vc.StandardMultiplier == multiplierID)&lt;br /&gt;        .Join(dc.Vm_Customers,&lt;br /&gt;              (vcm =&amp;gt; vcm.VisualCustomerID),&lt;br /&gt;              (vc =&amp;gt; vc.ID),&lt;br /&gt;              ((vcm, vc) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierCustomer&lt;br /&gt;              {&lt;br /&gt;                  VisualCustomerID = vcm.VisualCustomerID,&lt;br /&gt;                  CompanyName = vc.NAME,&lt;br /&gt;                  Brand = vcm.Website,&lt;br /&gt;                  MultiplierType = &lt;span class="str"&gt;&amp;quot;Standard&amp;quot;&lt;/span&gt;&lt;br /&gt;              }));&lt;br /&gt;IQueryable&amp;lt;MultiplierCustomer&amp;gt; QSCustomers =&lt;br /&gt;    dc.Pm_VisualCustMultipliers&lt;br /&gt;        .Where(vcm =&amp;gt; vcm.RecordDeleted == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;        .Where(vc =&amp;gt; vc.QSMultiplier == multiplierID)&lt;br /&gt;        .Join(dc.Vm_Customers,&lt;br /&gt;              (vcm =&amp;gt; vcm.VisualCustomerID),&lt;br /&gt;              (vc =&amp;gt; vc.ID),&lt;br /&gt;              ((vcm, vc) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierCustomer&lt;br /&gt;              {&lt;br /&gt;                  VisualCustomerID = vcm.VisualCustomerID,&lt;br /&gt;                  CompanyName = vc.NAME,&lt;br /&gt;                  Brand = vcm.Website,&lt;br /&gt;                  MultiplierType = &lt;span class="str"&gt;&amp;quot;QuickShip&amp;quot;&lt;/span&gt;&lt;br /&gt;              }));&lt;br /&gt;IQueryable&amp;lt;MultiplierCustomer&amp;gt; PartsCustomers =&lt;br /&gt;    dc.Pm_VisualCustMultipliers&lt;br /&gt;        .Where(vcm =&amp;gt; vcm.RecordDeleted == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;        .Where(vc =&amp;gt; vc.PartsMultiplier == multiplierID)&lt;br /&gt;        .Join(dc.Vm_Customers,&lt;br /&gt;              (vcm =&amp;gt; vcm.VisualCustomerID),&lt;br /&gt;              (vc =&amp;gt; vc.ID),&lt;br /&gt;              ((vcm, vc) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierCustomer&lt;br /&gt;              {&lt;br /&gt;                  VisualCustomerID = vcm.VisualCustomerID,&lt;br /&gt;                  CompanyName = vc.NAME,&lt;br /&gt;                  Brand = vcm.Website,&lt;br /&gt;                  MultiplierType = &lt;span class="str"&gt;&amp;quot;Parts&amp;quot;&lt;/span&gt;&lt;br /&gt;              }));&lt;br /&gt;IQueryable&amp;lt;MultiplierCustomer&amp;gt; StdBreakCustomers =&lt;br /&gt;    dc.Pm_VisualCustMultipliers&lt;br /&gt;        .Where(vcm =&amp;gt; vcm.RecordDeleted == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;        .Where(vc =&amp;gt; vc.StdBreakMultiplier == multiplierID)&lt;br /&gt;        .Join(dc.Vm_Customers,&lt;br /&gt;              (vcm =&amp;gt; vcm.VisualCustomerID),&lt;br /&gt;              (vc =&amp;gt; vc.ID),&lt;br /&gt;              ((vcm, vc) =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MultiplierCustomer&lt;br /&gt;              {&lt;br /&gt;                  VisualCustomerID = vcm.VisualCustomerID,&lt;br /&gt;                  CompanyName = vc.NAME,&lt;br /&gt;                  Brand = vcm.Website,&lt;br /&gt;                  MultiplierType = &lt;span class="str"&gt;&amp;quot;Standard Break&amp;quot;&lt;/span&gt;&lt;br /&gt;              }));&lt;br /&gt;List&amp;lt;MultiplierCustomer&amp;gt; usageList =&lt;br /&gt;    StdCustomers&lt;br /&gt;    .Concat(QSCustomers)&lt;br /&gt;    .Concat(PartsCustomers)&lt;br /&gt;    .Concat(StdBreakCustomers)&lt;br /&gt;    .ToList();&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;What's neat is that it really does build the SQL that you'd want, doing a UNION ALL on the individual LINQ queries, so that you send one query to the database. Here's the generated SQL:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t10].[VisualCustomerID], [t10].[NAME] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [CompanyName], [t10].[Website] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Brand], [t10].[&lt;span class="kwrd"&gt;value&lt;/span&gt;] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [MultiplierType]&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; (&lt;br /&gt;    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t7].[VisualCustomerID], [t7].[NAME], [t7].[Website], [t7].[&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; (&lt;br /&gt;        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t4].[VisualCustomerID], [t4].[NAME], [t4].[Website], [t4].[&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; (&lt;br /&gt;            &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t0].[VisualCustomerID], [t1].[NAME], [t0].[Website], @p1 &lt;span class="kwrd"&gt;AS&lt;/span&gt; [&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;            &lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[pm_VisualCustMultipliers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t0]&lt;br /&gt;            &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; [dbo].[vm_Customers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t1] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [t0].[VisualCustomerID] = [t1].[ID]&lt;br /&gt;            &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; ([t0].[StandardMultiplier] = @p0) &lt;span class="kwrd"&gt;AND&lt;/span&gt; (&lt;span class="kwrd"&gt;NOT&lt;/span&gt; ([t0].[RecordDeleted] = 1))&lt;br /&gt;            &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t2].[VisualCustomerID], [t3].[NAME], [t2].[Website], @p3 &lt;span class="kwrd"&gt;AS&lt;/span&gt; [&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;            &lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[pm_VisualCustMultipliers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t2]&lt;br /&gt;            &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; [dbo].[vm_Customers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t3] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [t2].[VisualCustomerID] = [t3].[ID]&lt;br /&gt;            &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; ([t2].[QSMultiplier] = @p2) &lt;span class="kwrd"&gt;AND&lt;/span&gt; (&lt;span class="kwrd"&gt;NOT&lt;/span&gt; ([t2].[RecordDeleted] = 1))&lt;br /&gt;            ) &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t4]&lt;br /&gt;        &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t5].[VisualCustomerID], [t6].[NAME], [t5].[Website], @p5 &lt;span class="kwrd"&gt;AS&lt;/span&gt; [&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;        &lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[pm_VisualCustMultipliers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t5]&lt;br /&gt;        &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; [dbo].[vm_Customers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t6] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [t5].[VisualCustomerID] = [t6].[ID]&lt;br /&gt;        &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; ([t5].[PartsMultiplier] = @p4) &lt;span class="kwrd"&gt;AND&lt;/span&gt; (&lt;span class="kwrd"&gt;NOT&lt;/span&gt; ([t5].[RecordDeleted] = 1))&lt;br /&gt;        ) &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t7]&lt;br /&gt;    &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [t8].[VisualCustomerID], [t9].[NAME], [t8].[Website], @p7 &lt;span class="kwrd"&gt;AS&lt;/span&gt; [&lt;span class="kwrd"&gt;value&lt;/span&gt;]&lt;br /&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; [dbo].[pm_VisualCustMultipliers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t8]&lt;br /&gt;    &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; [dbo].[vm_Customers] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t9] &lt;span class="kwrd"&gt;ON&lt;/span&gt; [t8].[VisualCustomerID] = [t9].[ID]&lt;br /&gt;    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; ([t8].[StdBreakMultiplier] = @p6) &lt;span class="kwrd"&gt;AND&lt;/span&gt; (&lt;span class="kwrd"&gt;NOT&lt;/span&gt; ([t8].[RecordDeleted] = 1))&lt;br /&gt;    ) &lt;span class="kwrd"&gt;AS&lt;/span&gt; [t10]&lt;br /&gt;&lt;span class="rem"&gt;-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [2]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p1: Input NVarChar (Size = 8; Prec = 0; Scale = 0) [Standard]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [2]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p3: Input NVarChar (Size = 9; Prec = 0; Scale = 0) [QuickShip]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p4: Input Int (Size = 0; Prec = 0; Scale = 0) [2]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p5: Input NVarChar (Size = 5; Prec = 0; Scale = 0) [Parts]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p6: Input Int (Size = 0; Prec = 0; Scale = 0) [2]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- @p7: Input NVarChar (Size = 14; Prec = 0; Scale = 0) [Standard Break]&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Proving, once again, that there's no substitute for checking the generated SQL when you're doing something twitchy with LINQ.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-5734649779482471618?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/5734649779482471618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=5734649779482471618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5734649779482471618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5734649779482471618'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/12/linq-of-day.html' title='LINQ of the Day'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-5736627309369225416</id><published>2008-12-08T11:53:00.009-05:00</published><updated>2008-12-12T13:18:56.832-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>It Ain't Rocket Surgery</title><content type='html'>&lt;p&gt;Or is it? And why should the rocket need surgery, anyway? And don't we all just love debugging stuff that fails intermittently, but always works correctly on our own machines? So it happened with WCF-based services for AJAX recently.&lt;/p&gt;  &lt;p&gt;This wasn't my first entanglement with ASP.NET's temporary files. The clue comes in various forms: You get a build error for a file that's right in front of you, and which compiles cleanly. You get a run-time error that says ASP.NET couldn't find a file that you &lt;em&gt;know&lt;/em&gt; is there. Except that it has a funny name, like &amp;quot;App_Web_zxemnnhw.5.cs&amp;quot;. That's an ASP.NET temporary file, and you'll find them in places like C:\Windows\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\breidert web\6d823db7\f71b84dd.&lt;/p&gt;  &lt;p&gt;The problem is that ASP.NET decides that it can leave some source code to be compiled-on-demand, even at run time. It doesn't seem to affect code-behinds, or code (anywhere in the web project or web application) that is called directly from code-behinds. The issue sneaks in when code in the web application project is only referenced in web.config - things like providers, HTTP modules, or services. This time, the nasty pointy snarly teeth belonged to a WCF service. (Check it out; you can embed WCF services directly in your web application. Right-click on the project or on a folder inside the project, click &amp;quot;Add -&amp;gt; New Item...&amp;quot;, and add a web service or a WCF service. This is in VS 2008, where all web apps are AJAX-enabled.)&lt;/p&gt;  &lt;p&gt;What you get is a pair of files, one called &amp;quot;MyServiceThing.svc&amp;quot; and a code-behind, &amp;quot;MyServiceThing.svc.cs&amp;quot;. You also get some new references and a &amp;lt;system.serviceModel&amp;gt; section in web.config that contains behaviors and bindings for your WCF service. (To use your new service, you'll need to code a service reference in your ScriptManager tag for ASP.NET AJAX.) &lt;/p&gt;  &lt;p&gt;And there the problem begins, because there is no direct call or reference to your service code in your C# (or VB) code. ASP.NET figures that it can stash this code in its temporary files, and compile on demand. But wait! There's more! This is a development or staging machine, and you're going to publish to a web server, and maybe copy from there to a production machine. That's where the ASP.NET temporary files get lost, because they don't seem to tag along with the publishing and deployment process. (Note that sometimes the problem doesn't even take this much effort to throw errors in your face. Gotta love it when a project builds cleanly but publishes with errors.)&lt;/p&gt;  &lt;p&gt;When you encounter problems with ASP.NET temporary files, there's a simple solution: Move the code to a separate project, and reference the project in your web app. &lt;/p&gt;  &lt;p&gt;For WCF services, it gets a little trickier because of the interplay between hosting and ASP.NET AJAX. You need that .svc file, and it needs to stay in your web project. That is specifically an ASP.NET web &amp;quot;page&amp;quot;, and it includes an ASP.NET declaration:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="asp"&gt;&amp;lt;%@ ServiceHost Language=&amp;quot;C#&amp;quot; Debug=&amp;quot;true&amp;quot; &lt;br /&gt;    Service=&amp;quot;NorthwindLINQ.MyServiceThing&amp;quot; &lt;br /&gt;    CodeBehind=&amp;quot;MyServiceThing.svc.cs&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;So to move the WCF service out of the web app, you only want to move the code-behind to a new project. Leave the .svc file where it is, delete the CodeBehind reference and file, and make sure the Service reference is the fully qualified class name of the service.&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="asp"&gt;&amp;lt;%@ ServiceHost Language=&amp;quot;C#&amp;quot; Debug=&amp;quot;true&amp;quot; &lt;br /&gt;    Service=&amp;quot;NorthwindLINQ.Services.MyServiceThing&amp;quot; %&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;Note that this declaration type is &amp;quot;ServiceHost&amp;quot;. This is how WCF services get hosted in an ASP.NET application. Hosting is a critical aspect of WCF, and ASP.NET pretty much takes care of that for you. The constraint is that you're not building a general-purpose service that anyone can call; it's going to be restricted to your web app. On the other hand, it goes through the full ASP.NET pipeline, so it has access to authentication and authorization status, session data, etc.&lt;/p&gt;&lt;p&gt;Also, make sure your ScriptManager tag points to the .svc file:&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt;  &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ScriptManager&amp;quot;&lt;/span&gt; &lt;br /&gt;     &lt;span class="attr"&gt;EnablePageMethods&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;br /&gt;    &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;server&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;EnablePartialRendering&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Scripts&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptReference&lt;/span&gt; &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;~/jscripts/myStuff.js&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Scripts&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ServiceReference&lt;/span&gt; &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;~/someFolder/MyServiceThing.svc&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;Check your web.config; you may not have to change the serviceModel there, but it's good to verify rather than trust. Things to watch for include the fully qualified class (service) name, and the reference to the service contract. Yes, it's OK for the address to be an empty string; ASP.NET takes care of that for you. ASP.NET AJAX supports only webHttpBinding, and you don't need a metadata binding.&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpointBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;NorthwindLINQ.Services.NorthwindLINQAspNetAjaxBehavior&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;enableWebScript&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;endpointBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceHostingEnvironment&lt;/span&gt; &lt;span class="attr"&gt;aspNetCompatibilityEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;NorthwindLINQ.Services.MyServiceThing&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;br /&gt;         &lt;span class="attr"&gt;behaviorConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;NorthwindLINQ.Services.NorthwindLINQAspNetAjaxBehavior&amp;quot;&lt;/span&gt;&lt;br /&gt;         &lt;span class="attr"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;webHttpBinding&amp;quot;&lt;/span&gt; &lt;br /&gt;         &lt;span class="attr"&gt;contract&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;NorthwindLINQ.Services.IMyServiceThing&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;Next comes the question of adding services in a separate project. WCF has its own way of doing this, and it's not really what we want. The project can be a normal class library. When you add a web service to a class library, Visual Studio creates an interface file and a class file (but no .svc file, since that's specific to ASP.NET). It also creates an app.config and puts the WCF binding in it. Get rid of the app.config file, since the bindings you want are already in web.config, and you don't want any other bindings making the service available to any other callers and/or hackers.&lt;/p&gt;&lt;p&gt;When you add a WCF service to ASP.NET, you don't get an interface file for the service contract. When you add a WCF service to a class library, you do get the interface file. I like interface files for service contracts. (You'll have to modify the contract name in web.config to point to the interface.) However you do it, though, you will probably want to modify the contract attributes. Here's a sample interface with service contract:&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; NorthwindLINQ.Services&lt;br /&gt;{&lt;br /&gt;    [ServiceContract(Namespace = &lt;span class="str"&gt;&amp;quot;NorthwindLINQ.Web&amp;quot;&lt;/span&gt;, Name = &lt;span class="str"&gt;&amp;quot;ThingService&amp;quot;&lt;/span&gt;)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IMyServiceThing&lt;br /&gt;    {&lt;br /&gt;        [OperationContract]&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; DoWork(&lt;span class="kwrd"&gt;string&lt;/span&gt; thing);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;And here's the associated class file:&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; NorthwindLINQ.Services&lt;br /&gt;{&lt;br /&gt;    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyServiceThing : IMyServiceThing&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; DoWork(&lt;span class="kwrd"&gt;string&lt;/span&gt; thing)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.isNullOrEmpty(thing))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Service tantrum&amp;quot;&lt;/span&gt;);&lt;br /&gt;                }&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; thing + &lt;span class="str"&gt;&amp;quot; : Done!&amp;quot;&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;{0}: {1}&amp;quot;&lt;/span&gt;, ex.GetType(), ex.Message));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;The namespace and name parameters on the service contract are important; these are the namespace and class names that ASP.NET AJAX will use to construct a proxy for calling your service. The AspNetCompatibilityRequirements attribute is also important so that WCF and ASP.NET AJAX will work smoothly together.&lt;/p&gt;&lt;p&gt;Calling your service from Javascript is easy, finally:&lt;/p&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; PageLoad()&lt;br /&gt;{&lt;br /&gt;    NorthwindLINQ.Web.ThingService.DoWork(&lt;span class="str"&gt;"whatever"&lt;/span&gt;, onCompleted, onError);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; onCompleted(results, context, methodName) {&lt;br /&gt;    alert(methodName + " : " + results);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; onError(errorInfo, context, methodName) {&lt;br /&gt;    alert(methodName + " : " + errorInfo);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;p&gt;onCompleted and onError will have either your results, or the error info, respectively. Note that you call the service using the namespace and class specified in the service contract.&lt;/p&gt;&lt;p&gt;And that's the rocket surgery to fix the ASP.NET temporary files problem for WCF services.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt;You know what? It still doesn't fix everything! The .svc file that remains in the web project is still subject to ASP.NET temporary file madness.&lt;/p&gt;&lt;p&gt;So if you have temporary file problems, there's always "Clean Solution" followed by "Rebuild Solution." If that fails, then next time I'm calling a &lt;i&gt;real&lt;/i&gt; rocket surgeon.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-5736627309369225416?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/5736627309369225416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=5736627309369225416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5736627309369225416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/5736627309369225416'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/12/it-ain-rocket-surgery.html' title='It Ain&amp;#39;t Rocket Surgery'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-7608479291430348747</id><published>2008-11-28T10:40:00.002-05:00</published><updated>2008-11-28T11:14:52.346-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Barkburn</title><content type='html'>&lt;p&gt;Many years ago, I attended an excellent course on project leadership. They had a term called &amp;quot;barkburn.&amp;quot; You know the people who can't see the forest for the trees? People with barkburn can't see the tree because their face is buried in the bark.&lt;/p&gt;  &lt;p&gt;The other night, after a .NET SIG meeting, we got in a discussion of testing, and particularly the relationship between unit testing (including Test-Driven Design) versus the kind of large-scale architectural and design issues that tend to interest me. And of course, quality issues always bring up the space shuttle, where many software engineering and quality practices originated. In email after the discussion, someone referenced &lt;a href="http://stephan.reposita.org/archives/2008/11/17/unit-testing-tdd-and-the-shuttle-disaster/"&gt;Unit Testing, TDD and the Shuttle Disaster&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;A couple of thoughts on the shuttle&amp;#8230;.&lt;/p&gt;  &lt;p&gt;Unit testing is certainly not a new idea. TDD is just a another&amp;#160; way of doing it. And it is certainly true that hardware gets unit and component testing as well as integration testing and component testing. Nothing at all new about this. And test specs getting written before development isn&amp;#8217;t new, either in software or hardware. Some hardware units in any design and early production are designated specifically for testing, often testing to destruction. There&amp;#8217;s rarely anything new under the sun.&lt;/p&gt;  &lt;p&gt;NASA&amp;#8217;s history prior to the shuttle included the Saturn V rocket, which was developed on a very accelerated schedule. Part of that schedule acceleration included grouping of component and integration tests with system test &amp;#8211; first test of some components and integration consisted of flying the first rocket. They called it &amp;#8220;all up&amp;#8221; testing. And it worked reasonably well; the first manned Saturn V flight was only the third flight of the rocket, and there were no failures in the entire life of the Saturn V. There was only one serious problem that occurred in any flights, a &amp;#8220;pogo&amp;#8221; vibration in the second stage that occurred in Apollo 6 (unmanned) and Apollo 13. Apollo 12&amp;#8217;s Saturn V survived a lightning strike during liftoff.&lt;/p&gt;  &lt;p&gt;Compare that to the shuttle. Both Challenger and Columbia failures shared a common root cause: stacking the shuttle side-by-side with its boosters and fuel tank, instead of the usual vertical stack. The Challenger break-up occurred because of asymmetric aerodynamic forces, due to trying to fly sideways as the boosters and fuel tank came apart. While an o-ring failure on a vertical stack would also have probably lost the launch stage, an Apollo-type design would have left the crew vehicle on-axis with the booster thrust changes, and the Apollo (as well as Mercury and Gemini) had an escape rocket to pull the crew vehicle away from a failing booster. The o-ring failure might well have been survivable in a vertical stack.&lt;/p&gt;  &lt;p&gt;As for Columbia&amp;#8230;. Ice shedding during launch is utterly routine. Ice builds up on the storage tanks for any rocket fueled by liquid oxygen. The foam was there only to protect the shuttle in a side-by-side stack. In a vertical stack, this wouldn&amp;#8217;t have been a failure mode at all; it would have been just another routine launch.&lt;/p&gt;  &lt;p&gt;These are design failures, and you can&amp;#8217;t unit-test your way out of design flaws. As the Quality Assurance professionals have known for a long time, you can&amp;#8217;t test quality into a product. That&amp;#8217;s something the software industry tends to forget, on a fairly regular schedule.&lt;/p&gt;  &lt;p&gt;Ahhhh, time to get to work.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-7608479291430348747?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/7608479291430348747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=7608479291430348747' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7608479291430348747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/7608479291430348747'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/11/barkburn.html' title='Barkburn'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-8196274626668545892</id><published>2008-11-28T10:22:00.003-05:00</published><updated>2008-11-28T11:12:31.994-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ of the Day</title><content type='html'>&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; CustomerHasMultiplier(&lt;span class="kwrd"&gt;string&lt;/span&gt; ID)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; FSP.DC().Pm_VisualCustMultipliers&lt;br /&gt;                .Where(m =&amp;gt; m.Status == &lt;span class="str"&gt;&amp;quot;Active&amp;quot;&lt;/span&gt;)&lt;br /&gt;                .Where(m =&amp;gt; m.RecordDeleted == &lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;                .Any(m =&amp;gt; m.VisualCustomerID == ID);&lt;br /&gt;        }&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;/pre&gt;All I want to do is knock on the database's door and ask, &amp;quot;Is anybody home?&amp;quot; With SQL, that means setting up a connection, a command, a reader or a data adapter and a dataset, running a query to do a count(*) or at least check to see if any rows were returned. With LINQ, it's a one-statement function that returns a bool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-8196274626668545892?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/8196274626668545892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=8196274626668545892' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/8196274626668545892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/8196274626668545892'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/11/linq-of-day.html' title='LINQ of the Day'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-4583615696892270817</id><published>2008-03-03T11:01:00.004-05:00</published><updated>2008-03-03T11:30:55.481-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><title type='text'>Error logging</title><content type='html'>I'm currently working on hardening an ASP.NET web site, so I'll be posting on error-handling and security issues for a little while.&lt;br /&gt;&lt;br /&gt;One of the basics for this task is good error handling, so I'll start with event logging. You don't ever want your production web site to post error data (not even in comments, so don't think about hiding them in your HTML source, either). So what to do? Use the Windows event logs.&lt;br /&gt;&lt;br /&gt;Here's a simple event logger that does the job. Put it in your App_Code directory.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class Logger&lt;br /&gt;{&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Application name&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    private static string LogName = "MyApp";&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Default constructor.&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public Logger()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Set up EventSource for logging&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public static void InitLogger()&lt;br /&gt;    {&lt;br /&gt;        if (!EventLog.Exists(LogName))&lt;br /&gt;        {&lt;br /&gt;            EventLog.CreateEventSource("MyApp Web Tools", LogName);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Log any error data sent this way.&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="LogData"&amp;gt;Exception to be logged.&amp;lt;/param&amp;gt;&lt;br /&gt;    public static void Log(Exception LogData)&lt;br /&gt;    {&lt;br /&gt;        string LogMessage = LogData.GetType().ToString() + ": " +&lt;br /&gt;            LogData.Message + System.Environment.NewLine +&lt;br /&gt;            LogData.StackTrace;&lt;br /&gt;        EventLog.WriteEntry(LogName, LogMessage, EventLogEntryType.Error);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// Log an exception, plus additional data&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="LogData"&amp;gt;Exception to be logged&amp;lt;/param&amp;gt;&lt;br /&gt;    /// &amp;lt;param name="LogInfo"&amp;gt;Dictionary of string-string name-value pairs to &lt;br /&gt;    /// be included in the log entry&amp;lt;/param&amp;gt;&lt;br /&gt;    public static void Log(Exception LogData, Dictionary&amp;lt;string,&amp;gt; LogInfo)&lt;br /&gt;    {&lt;br /&gt;        StringBuilder _LogText = new StringBuilder();&lt;br /&gt;        _LogText.Append(LogData.GetType().ToString() + ": ");&lt;br /&gt;        _LogText.Append(LogData.Message + System.Environment.NewLine);&lt;br /&gt;        foreach(string Name in LogInfo.Keys)&lt;br /&gt;        {&lt;br /&gt;            _LogText.Append(String.Format("Name: {0}, Value{1}{2}",&lt;br /&gt;                Name, LogInfo[Name], System.Environment.NewLine));&lt;br /&gt;        }&lt;br /&gt;        _LogText.Append(LogData.StackTrace + System.Environment.NewLine);&lt;br /&gt;        EventLog.WriteEntry(LogName, _LogText.ToString(), EventLogEntryType.Error);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Note that the logger takes an exception as a parameter. There are a couple of nice things about this. One is that the exception contains a call stack, so your log can point you to the place where the exception occurred. Second, you can set up your application to catch unhandled exceptions, and log those, too, so you can get logs on errors that you didn't anticipate. (My next post will cover unhandled exceptions in detail.)&lt;br /&gt;&lt;br /&gt;Using this logging class is very easy. Somewhere in your initialization code, you need to call &lt;br /&gt;&lt;code&gt;&lt;br /&gt;    Logger.InitLogger();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Then, to log an event, throw an exception, catch it, and log it.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;    throw new Exception("Surprise!");&lt;br /&gt;}&lt;br /&gt;catch (Exception ex)&lt;br /&gt;{&lt;br /&gt;    Logger.Log(ex);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;How hard is that? You can find your log using either the Windows Event Viewer (in Computer -&gt; Manage) or in the Server Explorer in Visual Studio.&lt;br /&gt;&lt;br /&gt;Also note that the Log method is overloaded. The second version adds a dictionary as a second parameter; you can load up the dictionary with name-value pairs (both as strings) so your event log will contain data values that you'd like to save with the exception message and call stack. Make your logs as informative as possible!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-4583615696892270817?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/4583615696892270817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=4583615696892270817' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/4583615696892270817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/4583615696892270817'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/03/error-logging.html' title='Error logging'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-616657624096468492</id><published>2008-02-12T22:44:00.005-05:00</published><updated>2008-02-15T22:07:51.598-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Slides posted</title><content type='html'>The slides are now available as well, in both &lt;a href="http://www.firelily.com/linq/LINQforEnterpriseApps.zip"&gt;PowerPoint 2007 format (zipped)&lt;/a&gt; and &lt;a href="http://www.firelily.com/linq/LINQforEnterpriseApps.pdf"&gt;PDF format (2MB)&lt;/a&gt;. There may be minor tweaks again before the presentation, but this is pretty much the script.&lt;br /&gt;&lt;br /&gt;ETA: Slides have been updated for the Raleigh Code Camp.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-616657624096468492?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/616657624096468492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=616657624096468492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/616657624096468492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/616657624096468492'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/02/slides-posted.html' title='Slides posted'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-3093111181898463313</id><published>2008-02-12T21:20:00.001-05:00</published><updated>2008-02-13T16:36:28.766-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Sample code posted</title><content type='html'>The &lt;a href="http://www.firelily.com/linq/NorthwindLINQ.zip"&gt;sample code&lt;/a&gt; is available for my LINQ presentation.&lt;br /&gt;&lt;br /&gt;This requires Visual Studio 2008, SQL Server 2000 or 2005, as well as the Northwind database. I used the "extended" Northwind that was temporarily distributed for LINQ, but I don't think anything in the sample actually requires it. It's available &lt;a href="http://www.linqdev.com/"&gt;here&lt;/a&gt;; just look down the page.&lt;br /&gt;&lt;br /&gt;The samples include a lot of good stuff! Complex queries, N-tier application prototypes (including compiled queries, caching, isolating the presentation layer, full CRUD operations, and optimistic concurrency support), queries to DataSet objects, stored procedure examples, non-flat result sets, and more.&lt;br /&gt;&lt;br /&gt;Slides to follow "soon", for appropriate values of "soon."&lt;br /&gt;&lt;br /&gt;ETA: One sample program does require the "extended" Northwind. It's SprocTwoResults.aspx, which calls a stored procedure that's not in the "standard" Northwind.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-3093111181898463313?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/3093111181898463313/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=3093111181898463313' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/3093111181898463313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/3093111181898463313'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/02/sample-code-posted.html' title='Sample code posted'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4800634963970790114.post-6586999747057226416</id><published>2008-02-11T09:49:00.000-05:00</published><updated>2008-02-11T09:56:37.410-05:00</updated><title type='text'>Getting Started</title><content type='html'>This is a first post, just getting things started for this blog. I'll be giving a presentation on LINQ at the &lt;a href="http://www.trinug.org/"&gt;local .NET user group&lt;/a&gt; this week. I'll be posting links for the presentation and sample code in a few days. Then I'll go into details on some of the sample code, and get into the bits and bytes of it all.&lt;br /&gt;&lt;br /&gt;LINQ is an exciting new technology; it has really changed how I think about writing software. Already, I'm finding that I think about solutions in terms of how LINQ can do it. When LINQ is not available, it really feels like a restraint! (And not in a good way...)&lt;br /&gt;&lt;br /&gt;More to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4800634963970790114-6586999747057226416?l=toomanylayers.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://toomanylayers.blogspot.com/feeds/6586999747057226416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=4800634963970790114&amp;postID=6586999747057226416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/6586999747057226416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4800634963970790114/posts/default/6586999747057226416'/><link rel='alternate' type='text/html' href='http://toomanylayers.blogspot.com/2008/02/getting-started.html' title='Getting Started'/><author><name>Diane Wilson</name><uri>http://www.blogger.com/profile/03075384770362237247</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp3.blogger.com/_MCb1sqB-e7o/R7EOcmh-JUI/AAAAAAAAAAc/SK1_eFqXK3M/S220/snazzy.jpg'/></author><thr:total>0</thr:total></entry></feed>
