<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"><title type="html">LightSwitch Rocks!</title><subtitle type="html" /><id>http://blogs.msdn.com/b/lightswitch_rocks1/atom.aspx</id><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/lightswitch_rocks1/" /><link rel="self" type="application/atom+xml" href="http://blogs.msdn.com/b/lightswitch_rocks1/atom.aspx" /><generator uri="http://telligent.com" version="5.6.50428.7875">Telligent Evolution Platform Developer Build (Build: 5.6.50428.7875)</generator><updated>2011-07-08T19:24:00Z</updated><entry><title>OData Consumption Validation in Visual Studio LightSwitch 2012</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/lightswitch_rocks1/archive/2012/07/05/odata-consumption-validation-in-visual-studio-lightswitch-2012.aspx" /><id>http://blogs.msdn.com/b/lightswitch_rocks1/archive/2012/07/05/odata-consumption-validation-in-visual-studio-lightswitch-2012.aspx</id><published>2012-07-05T21:18:00Z</published><updated>2012-07-05T21:18:00Z</updated><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;OData Feed Query Support&lt;/h4&gt;
&lt;p&gt;Now that &lt;a href="http://msdn.microsoft.com/en-us/lightswitch/hh852657"&gt;LightSwitch in Visual Studio 2012&lt;/a&gt; supports the ability to consume &lt;a href="http://www.odata.org/"&gt;OData feeds&lt;/a&gt;, there are a wide variety of feeds that can be used to build interesting LightSwitch applications, ranging from NetFlix to Dynamics CRM. However, it&amp;rsquo;s important to remember that all feeds are not equal &amp;ndash; each one may have varying levels of support for the underlying OData query operators that LightSwitch applications rely on.&lt;/p&gt;
&lt;p&gt;When a LightSwitch application consumes a feed that doesn&amp;rsquo;t support one of the OData query operators, typically the data will fail to display. As a result, the user will see a red-X with a tooltip saying &amp;ldquo;Unable to load data. Please check your network connection and try loading again.&amp;rdquo; The diagnostics log will also display the error message that is returned by the feed. For more information on how to use the diagnostic log to troubleshoot red-x&amp;rsquo;s, refer to Eric Erhardt&amp;rsquo;s blog post: &lt;a href="http://blogs.msdn.com/b/lightswitch/archive/2011/09/20/diagnosing-problems-in-a-deployed-lightswitch-application-eric-erhardt.aspx"&gt;Diagnosing Problems in a Deployed 3-Tier LightSwitch Application&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The good news is that even though few feeds support all of the OData query operators, a majority of LightSwitch's core query features do in fact work with the feeds. Furthermore, design time options can be set to prevent a red-X experience when an operator isn&amp;rsquo;t supported by a feed. To help with this, the LightSwitch OData Attach wizard does work behind the scenes to set these options appropriately.&amp;nbsp; This wizard is opened by right-clicking the server project and selecting &amp;ldquo;Add Data Source&amp;hellip;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/7103.ODataAttach_5F00_196DC409.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Attach Wizard - OData" border="0" alt="Attach Wizard - OData" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5543.ODataAttach_5F00_thumb_5F00_6B143E5B.png" width="244" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a name="_msocom_1"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&amp;ldquo;Search&amp;rdquo; and &amp;ldquo;Eager-Load&amp;rdquo; Design Time Options&lt;/h4&gt;
&lt;p&gt;Using the feeds that are currently available within the OData ecosystem, you&amp;rsquo;ll find that many of the feeds:&lt;/p&gt;
&lt;p&gt;&amp;middot; Do not support the ability to search entity string properties&lt;/p&gt;
&lt;p&gt;&amp;middot; Do not support the ability to eager-load related entity data&lt;/p&gt;
&lt;p&gt;Based on this, the OData Attach wizard automatically sets options that correspond to these features to &amp;ldquo;off&amp;rdquo; for all feeds (with the exception of LightSwitch produced feeds). This means there may occasionally be a feed that does support these features, yet its design time option is turned &amp;ldquo;off&amp;rdquo;. In this case, you still have the ability to turn the feature back &amp;ldquo;on&amp;rdquo; by simply changing the corresponding option.&lt;/p&gt;
&lt;p&gt;The remainder of this section explains the design time options for these features in further detail and how they are set by the OData Attach wizard.&lt;/p&gt;
&lt;h6&gt;Performing Searches&lt;/h6&gt;
&lt;p&gt;To perform searches, LightSwitch uses the following &lt;a href="http://www.odata.org/documentation/uri-conventions"&gt;query operators&lt;/a&gt; from the OData protocol:&lt;/p&gt;
&lt;p&gt;&amp;middot; $SubstringOf function&lt;/p&gt;
&lt;p&gt;&amp;middot; $Filter query option&lt;/p&gt;
&lt;p&gt;&amp;middot; OR-boolean operator&lt;/p&gt;
&lt;p&gt;These are used to perform searches on each searchable string property defined on an entity.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/8255.Search_5F00_51AC3B21.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Search - Screen" border="0" alt="Search - Screen" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/3301.Search_5F00_thumb_5F00_384437E7.png" width="244" height="171" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If a feed doesn&amp;rsquo;t support both the $SubstringOf and OR-boolean operator within a $Filter query option, then LightSwitch searches cannot be performed against the feed. Since many feeds don&amp;rsquo;t support this, the OData Attach wizard automatically turns &amp;ldquo;off&amp;rdquo; search by:&lt;/p&gt;
&lt;p&gt;&amp;middot; Unchecking the &amp;ldquo;Is Searchable&amp;rdquo; option on entities&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1731.SearchableOptionEntity_5F00_70EEE1F4.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Entity Search Option" border="0" alt="Entity Search Option" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6518.SearchableOptionEntity_5F00_thumb_5F00_05743173.png" width="244" height="168" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;middot; Unchecking the &amp;ldquo;Support Search&amp;rdquo; option for corresponding screen members&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1234.SearchableOption_5F00_571AABC5.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Screen Search Option" border="0" alt="Screen Search Option" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6012.SearchableOption_5F00_thumb_5F00_36936C13.png" width="244" height="174" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can turn search back &amp;ldquo;on&amp;rdquo; by checking both of the above options.&lt;/p&gt;
&lt;p&gt;Note that turning search &amp;ldquo;on&amp;rdquo; for fields can impact performance. For further information, refer to Beth Massi&amp;rsquo;s blog post: &lt;a href="http://blogs.msdn.com/b/bethmassi/archive/2012/05/29/lightswitch-tips-amp-tricks-on-query-performance.aspx"&gt;LightSwitch Tips and Tricks on Query Performance&lt;/a&gt;.&lt;/p&gt;
&lt;h6&gt;Eager-Loading Data&lt;/h6&gt;
&lt;p&gt;To eager-load related entity data, LightSwitch uses the &lt;a href="http://www.odata.org/documentation/uri-conventions#ExpandSystemQueryOption"&gt;$Expand query option&lt;/a&gt;. This query option is used to eager-load many-to-one and many-to-zero or one navigation properties to related entities. For example, for a screen that displays both Order and related Shipper data, these operators are used to fetch both the Order and Shipper data in the same request to optimize performance.&lt;/p&gt;
&lt;p&gt;Since many feeds don&amp;rsquo;t support the $Expand operator, the OData Attach wizard automatically turns &amp;ldquo;off&amp;rdquo; eager-loading by unchecking the &amp;ldquo;Display by Default&amp;rdquo; option that is available on navigation properties in the entity designer.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5123.DisplayByDefault_5F00_3627391E.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Display By Default Option" border="0" alt="Display By Default Option" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6082.DisplayByDefault_5F00_thumb_5F00_7CA42926.png" width="244" height="115" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can turn eager-loading back &amp;ldquo;on&amp;rdquo; by checking the &amp;ldquo;Display by Default&amp;rdquo; option.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;&amp;ldquo;Paging&amp;rdquo; and &amp;ldquo;Page Count&amp;rdquo; Design Time Options&lt;/h4&gt;
&lt;p&gt;The OData Attach wizard also executes several queries to determine whether a feed supports:&lt;/p&gt;
&lt;p&gt;&amp;middot; Requesting a page of data&lt;/p&gt;
&lt;p&gt;&amp;middot; Counting how many total pages of data exist&lt;/p&gt;
&lt;p&gt;The design time options for these features are only turned &amp;ldquo;off&amp;rdquo; if they aren&amp;rsquo;t supported by the feed; otherwise they are left &amp;ldquo;on&amp;rdquo;. These query checks are performed using the first entity that is selected in the &amp;ldquo;Choose your Entities&amp;rdquo; screen of the wizard.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/8156.ChooseEntities_5F00_4A4055A7.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Choose Entities" border="0" alt="Choose Entities" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/0310.ChooseEntities_5F00_thumb_5F00_49D422B2.png" width="244" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The remainder of this section explains the design time options for these features in further detail and how they are set by the OData Attach wizard.&lt;/p&gt;
&lt;h6&gt;Requesting Page of Data&lt;/h6&gt;
&lt;p&gt;To request a page of data, LightSwitch uses the &lt;a href="http://www.odata.org/documentation/uri-conventions#TopSystemQueryOption"&gt;$Top query option&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/3750.Paging_5F00_6D8D4A4C.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Paging" border="0" alt="Paging" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/8156.Paging_5F00_thumb_5F00_340A3A55.png" width="244" height="189" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The OData Attach wizard issues a $Top query to determine whether it is supported by the feed. If the $Top query fails with a 500 error, the &amp;ldquo;Support Paging&amp;rdquo; option is unchecked for the screen member. Otherwise, the option is checked.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/7658.ScreenDesignerPaging_5F00_28747D16.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Support Paging Option" border="0" alt="Support Paging Option" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5187.ScreenDesignerPaging_5F00_thumb_5F00_7A1AF768.png" width="244" height="162" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h6&gt;Counting Pages of Data&lt;/h6&gt;
&lt;p&gt;To count how many pages of data exist, LightSwitch uses the &lt;a href="http://www.odata.org/documentation/uri-conventions"&gt;$Count query option&lt;/a&gt;. This information is displayed as part of the paging control on a list or grid (refer to screenshot X).&lt;/p&gt;
&lt;p&gt;The OData Attach wizard issues a $Count query to determine whether it is supported by the feed. If the $Count query fails with a 500 error, an option in the Common.lsml is set so that the number of total pages isn&amp;rsquo;t displayed as part of the paging control. This option isn&amp;rsquo;t surfaced through the design time environment.&lt;/p&gt;
&lt;h4&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4&gt;Read-Only OData Feeds&lt;/h4&gt;
&lt;p&gt;The OData Attach wizard includes an option used to specify whether the entire feed is read-only. Since a majority of OData feeds are read-only, this option is checked by default for all feeds, including LightSwitch produced feeds:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/3312.ODataAttach2_5F00_10764444.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Read-only Option" border="0" alt="Read-only Option" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2620.ODataAttach2_5F00_thumb_5F00_100A114F.png" width="244" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Setting this value results in the following:&lt;/p&gt;
&lt;p&gt;&amp;middot; Insert, Update, and Delete buttons are disabled on screens&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2043.ScreenButtons_5F00_46DEBDFF.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Screen Buttons" border="0" alt="Screen Buttons" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2364.ScreenButtons_5F00_thumb_5F00_519C1554.png" width="206" height="98" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;middot; The *_CanInsert, *_CanUpdate, and *_CanDelete access control methods are removed from the Write Code menu that is available on an entity and these methods will not be called if they are implemented in code&lt;/p&gt;
&lt;p&gt;&amp;middot; Insert, updates, and deletes to entities via code is prevented&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Although the functionality provided by OData feeds varies, LightSwitch helps with these inconsistencies by setting design time options to prevent a poor runtime experience. And, if needed, you still have the flexibility of setting these options.&lt;/p&gt;
&lt;p&gt;Special thanks to Matt Evans for providing some of the content included with this post.&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;Nicole Haugen&lt;ins datetime="2012-06-18T12:03" cite="mailto:Beth%20Massi"&gt;&lt;/ins&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10327279" width="1" height="1"&gt;</content><author><name>Nicole Haugen</name><uri>http://blogs.msdn.com/nicolehaugen79_4000_hotmail.com/ProfileUrlRedirect.ashx</uri></author><category term="Nicole Haugen" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Nicole+Haugen/" /><category term="LightSwitch" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/LightSwitch/" /><category term="Validation" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Validation/" /><category term="OData" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/OData/" /><category term="Consumption" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Consumption/" /></entry><entry><title>How To: Handle Database Concurrency Issues</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/08/19/how-to-handle-database-concurrency-issues.aspx" /><id>http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/08/19/how-to-handle-database-concurrency-issues.aspx</id><published>2011-08-19T02:10:24Z</published><updated>2011-08-19T02:10:24Z</updated><content type="html">&lt;p&gt;Concurrency issues are common in multi-user applications that have a database on the backend. Suppose you read a table record and then another user comes along and makes changes to the same record. Unless you re-read (e.g. refresh) your record, the data becomes stale. If you then attempt to make changes to the stale record, the application must detect and handle any data conflicts that may have occurred. For example, the other user may have modified the exact same field or may have even deleted the entire record. Clearly, the task of detecting and handling concurrency issues is not only important, but also quite complicated. &lt;/p&gt;  &lt;p&gt;The good news is that LightSwitch makes concurrency very easy to handle. In fact, you might say that LightSwitch turns concurrency issues into concurrency &lt;u&gt;non&lt;/u&gt;-issues. Specifically, LightSwitch provides a couple of different mechanisms for handling concurrency: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;When a conflict is detected, a “Data Conflict” screen is automatically displayed to the user allowing them to choose how to resolve the conflict &lt;/li&gt;    &lt;li&gt;Or, for a more customized solution, code can be written so that the application resolves the conflict without requiring interaction from the user&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To see how to use these mechanisms, let’s continue with the Expense Report Tracker application that I discussed in my &lt;a href="http://blogs.msdn.com/b/lightswitch_rocks1/"&gt;previous blog posts&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Display “Data Conflict” Screen&lt;/b&gt; &lt;/p&gt;  &lt;p&gt;First off, let’s look at what we need to do in order to have LightSwitch display the “Data Conflict” screen when a concurrency error occurs in the Expense Report Tracker application. The answer to this is…nothing! LightSwitch automatically does this for you without having to write any additional code. &lt;/p&gt;  &lt;p&gt;Since Expense Report Tracker is a multi-user application, it’s possible that two different managers might be reviewing the same expense report. If one of the managers decides to reject the expense report while the other decides to approve it, LightSwitch will detect the conflict. As a result, LightSwitch will display the following screen to the manager who was slowest to save their change: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/0247.image_5F00_72B2F7C6.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1323.image_5F00_thumb_5F00_1914DB12.png" width="453" height="247" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Or, if instead the first manager deletes an expense report while the second manager attempts to approve it, the second manager will see the following screen when they save: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/0825.clip_5F00_image002_5F00_11896BA5.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002" border="0" hspace="12" alt="clip_image002" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1727.clip_5F00_image002_5F00_thumb_5F00_3F0A8B68.jpg" width="244" height="189" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;b&gt;Write Code to Automatically Handle Conflict Resolution&lt;/b&gt; &lt;/p&gt;  &lt;p&gt;In some cases you may want your application to automatically handle conflict resolution so that the user never sees the “Data Conflict” screen. Again, LightSwitch makes this very simple by exposing several programming objects that can be used to resolve the conflict. &lt;/p&gt;  &lt;p&gt;When a data conflict is detected by LightSwitch’s server, it will throw a ConcurrencyException. &lt;/p&gt;  &lt;p&gt;You can then write code in the client that catches this exception and uses it to get the collection of entities that have data conflicts. From there, you have access to all of the entity property values and have the ability to indicate whether a change should be saved or discarded. &lt;/p&gt;  &lt;p&gt;With this in mind, suppose in the Expense Report Tracker that when two managers update an expense report to have the same status, that we want the code to automatically resolve the conflict. For example, if both managers set the status for the same expense report to “Approved”, then we don’t want the application to display the “Data Conflict” screen. Instead, we want our application to handle this automatically for the user. &lt;/p&gt;  &lt;p&gt;To do this, we will need to write code in the screen’s “Saving” method. This method allows us to override the default behavior that occurs when the user clicks the Save button on the screen. You can add code to this method by opening the screen’s designer and choosing the method from the “Write Code” menu: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6518.clip_5F00_image0024_5F00_7095F8FD.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image002[4]" border="0" alt="clip_image002[4]" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1212.clip_5F00_image0024_5F00_thumb_5F00_500EB94B.jpg" width="244" height="61" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Next, let’s add the following code to the “Saving” method. Notice that our code first attempts to save the changes. If no data conflicts are detected, the changes will be saved as normal. &lt;/p&gt;  &lt;p&gt;However, if a data conflict is detected, the server will throw a ConcurrencyException. Our code catches this exception and uses it to determine whether a conflict occurred with the Status property. In the case that two different users set the Status property to the exact same value, our code will automatically resolve the conflict by choosing to save the client’s value. &lt;/p&gt;  &lt;p&gt;Otherwise, if some other type of data conflict occurred, the user will still be prompted to resolve the conflict by displaying the “Data Conflict” screen. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;C#:&lt;/strong&gt;&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  partial &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ExpenseReportsListDetail_Saving(&lt;span style="color: #0000ff"&gt;ref&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; handled)
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  {
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       &lt;span style="color: #008000"&gt;//Indicates that our code will call SaveChanges()&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       handled = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       &lt;span style="color: #0000ff"&gt;try&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       {
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.DataWorkspace.ApplicationData.SaveChanges();
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       }
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       &lt;span style="color: #0000ff"&gt;catch&lt;/span&gt; (ConcurrencyException e)
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       {
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (IEntityObject entityConflict &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; e.EntitiesWithConflicts)
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;              {
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    EntityPropertyConflict statusProperty =
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    	               entityConflict.Details.EntityConflict.ConflictingProperties.Where(
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                       property =&amp;gt; property.Property.Name == &amp;quot;&lt;span style="color: #8b0000"&gt;Status&lt;/span&gt;&amp;quot;).Single();
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (statusProperty.Property.Value.ToString() == statusProperty.ServerValue.ToString())
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    {
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                        statusProperty.EntityConflict.ResolveConflicts(ConflictResolution.ClientWins);
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;//Resave once we’ve resolved the conflicts&lt;/span&gt;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.DataWorkspace.ApplicationData.SaveChanges();
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    }
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                }
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;          }
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;    }
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;strong&gt;VB:&lt;/strong&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;  Private Sub ExpenseReportDetail_Saving(ByRef handled As Boolean)
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       handled = True
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       Try
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            Me.DataWorkspace.ApplicationData.SaveChanges()
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;       Catch e As ConcurrencyException
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            For Each entityConflict As IEntityObject In e.EntitiesWithConflicts
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                Dim statusProperty As EntityPropertyConflict =
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    (From prop In   entityConflict.Details.EntityConflict.ConflictingProperties
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;               	     Where prop.Property.Name = &amp;quot;&lt;span style="color: #8b0000"&gt;Status&lt;/span&gt;&amp;quot;
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;               	     Select prop).Single()
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                If (statusProperty.Property.Value.ToString() = statusProperty.ServerValue.ToString()) Then
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    statusProperty.EntityConflict.ResolveConflicts(
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    ConflictResolution.ClientWins)
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                    Me.DataWorkspace.ApplicationData.SaveChanges()
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;                End If
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;            Next
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;        End Try
&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;p&gt;   End Sub
&lt;/p&gt;&lt;p&gt;&amp;#160;&lt;/p&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;There are a few things worth highlighting in the above code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Notice that this method accepts a “handled” parameter. When this parameter is set to true, this indicates that the code is responsible for calling SaveChanges() to save any changes that the user has made. Otherwise, if this parameter is false, LightSwitch automatically calls SaveChanges() for us. Since we want to handle saving on our own, the “handled” property is set to true. Also, notice that when a concurrency exception does occur, we must call SaveChanges() again to save the changes after we’ve resolved the concurrency conflicts.&lt;/li&gt;

  &lt;li&gt;You may have wondered why we didn’t try to catch and resolve the concurrency issue on the server, such as in the SaveChanges_ExecuteFailed method. The issue with this is that it is not valid to re-initiate a new Save from within the save pipeline once a failure has occurred. Instead, you must fix the concurrency issues and re-initiate the save from the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;LightSwitch makes concurrency extremely easy to implement. In most cases, you don’t even need to worry about concurrency issues when creating your application because LightSwitch will handle it all for you. However, if there are situations where you want to write code to automatically resolve the data conflicts for the user; LightSwitch provides an easy to use programming model that is accessible through the ConcurrencyException that is thrown from the server.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10197602" width="1" height="1"&gt;</content><author><name>Nicole Haugen</name><uri>http://blogs.msdn.com/nicolehaugen79_4000_hotmail.com/ProfileUrlRedirect.ashx</uri></author></entry><entry><title>How To: Using the Created Method to Set Default Property Values</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/08/09/how-to-using-the-created-method-to-set-default-property-values.aspx" /><id>http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/08/09/how-to-using-the-created-method-to-set-default-property-values.aspx</id><published>2011-08-09T00:51:00Z</published><updated>2011-08-09T00:51:00Z</updated><content type="html">&lt;p&gt;An extremely useful method that I consider to be a &amp;ldquo;must-have&amp;rdquo; in almost any type of LightSwitch application is the Created method. The Created method allows us to easily set the default values for an entity&amp;rsquo;s properties (e.g. fields in a table). To understand this further, let&amp;rsquo;s dive into an example that shows how to use the Created method.&lt;/p&gt;
&lt;p&gt;If you read my first blog post on how to Prevent a &lt;a href="http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/07/08/prevent-a-security-hole-with-access-control-part-i.aspx"&gt;Hole with Security Access Control&lt;/a&gt;, then you may remember in that scenario that I created a simple application used to track expense reports (which I creatively called the &amp;ldquo;Expense Report Tracker&amp;rdquo;). This application consists of two entities sharing a one-to-many relationship, called ExpenseReport and ExpenseItems. There are two types of users that use the application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Employees that create and save expense reports for approval&lt;/li&gt;
&lt;li&gt;Managers that approve or reject employees&amp;rsquo; expense reports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In addition, we have a couple of business rules for when an employee creates an expense report &amp;ndash; specifically, when an employee creates an expense report:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The ExpenseReport&amp;rsquo;s Name and UserAlias fields should be automatically set to the employee&amp;rsquo;s user information&lt;/li&gt;
&lt;li&gt;The ExpenseReport&amp;rsquo;s Status field should be automatically set to a &amp;ldquo;Pending&amp;rdquo; status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6886.image_5F00_1FE07FC1.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/1425.image_5F00_thumb_5F00_5F3E3351.png" width="378" height="157" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Created method allows us to implement both of the above business rules by using it to set the default values for the Name, UserAlias, and Status properties when the ExpenseReport entity is created. It&amp;rsquo;s important to note that the Created method is executed on both the Client and Server tier. As a result, the Created method is called no matter what mechanism is used to create an entity, regardless if it&amp;rsquo;s by clicking the &amp;ldquo;Add&amp;rdquo; button on a screen or by constructing an entity through code.&lt;/p&gt;
&lt;p&gt;To add the ExpenseReport&amp;rsquo;s Created method to our application, open the ExpenseReport entity in the designer and select the &amp;ldquo;ExpenseReport_Created&amp;rdquo; method from the &amp;ldquo;Write Code&amp;rdquo; drop-down menu&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5226.image_5F00_4C89399A.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5807.image_5F00_thumb_5F00_44FDCA2D.png" width="571" height="218" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the &amp;ldquo;ExpenseReport_Created&amp;rdquo; method&amp;rsquo;s code is generated, we can access the entity and set the properties&amp;rsquo; values using the following code:&lt;/p&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;C#:
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;partial &lt;span style="color: #0000ff;"&gt;void&lt;/span&gt; ExpenseReport_Created()
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;{
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;   &lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.Status = "&lt;span style="color: #8b0000;"&gt;Pending&lt;/span&gt;";
&lt;/pre&gt;
&lt;p&gt;&lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.Name = &lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.Application.User.FullName;&lt;/p&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;   &lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.UserAlias = &lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.Application.User.Name.Substring(
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;   &lt;span style="color: #0000ff;"&gt;this&lt;/span&gt;.Application.User.Name.LastIndexOf("&lt;span style="color: #8b0000;"&gt;\\&lt;/span&gt;") + 1);
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;}
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;VB:
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;&lt;span style="color: #0000ff;"&gt;Private&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;Sub&lt;/span&gt; ExpenseReport_Created()
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.Status = "&lt;span style="color: #8b0000;"&gt;Pending&lt;/span&gt;"
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; height: 17px; font-size: 12px;"&gt;    &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.Name = &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.Application.User.FullName
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.UserAlias = &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.Application.User.Name.Substring(
&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;        &lt;span style="color: #0000ff;"&gt;Me&lt;/span&gt;.Application.User.Name.LastIndexOf("\&lt;span style="color: #8b0000;"&gt;\") + 1 &lt;/span&gt;&lt;/pre&gt;
&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;&lt;span style="color: #0000ff;"&gt;End&lt;/span&gt; &lt;span style="color: #0000ff;"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Next, let&amp;rsquo;s add a screen, called CreateNewExpenseReport, The screen is used for creating Expense Reports that display the values of the Name, UserAlias, and Status properties. Since these values are set automatically for the user in the Created method, we don&amp;rsquo;t want the user to have to enter these values. Essentially, we want these values to be non-editable through the screen.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6708.image_5F00_045B7DBE.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/7875.image_5F00_thumb_5F00_4AD86DC6.png" width="603" height="179" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The easiest way to get this behavior is to use Label controls to display the Name, UserAlias, and Status properties. Label controls allow the user to view a value, but not edit it. To set the Control Type to Label, select the control in the screen designer and change the &amp;ldquo;Control Type&amp;rdquo; property to &amp;ldquo;Label&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2086.image_5F00_583E80CC.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5238.image_5F00_thumb_5F00_3BC18EEC.png" width="388" height="311" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s important to note that even though our screen prevents the user from entering values for the Name, UserAlias, and Status properties, these values aren&amp;rsquo;t protected from modification. To properly secure these values and ensure that an employee cannot modify them, we need to implement security access control checks in the save pipeline methods. Refer to my previous blog post for information on how to do this.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;As you can see from the above scenario, the Created method is extremely useful for setting default values for entity properties. In particular, setting default values in this manner helps save the end-user time so that they don&amp;rsquo;t have to enter data that the application can automatically detect and set for them.&lt;/p&gt;
&lt;p&gt;For a video demonstration of this technique see - &lt;a href="http://msdn.microsoft.com/en-us/lightswitch/hh307861"&gt;How Do I: Set Default Values on Fields when Entering New Data?&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10193855" width="1" height="1"&gt;</content><author><name>Nicole Haugen</name><uri>http://blogs.msdn.com/nicolehaugen79_4000_hotmail.com/ProfileUrlRedirect.ashx</uri></author><category term="Nicole Haugen" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Nicole+Haugen/" /><category term="Silverlight" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Silverlight/" /><category term="LightSwitch" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/LightSwitch/" /></entry><entry><title>Prevent a Security Hole with Access Control - Securing Logic Tier</title><link rel="alternate" type="text/html" href="http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/07/08/prevent-a-security-hole-with-access-control-part-i.aspx" /><id>http://blogs.msdn.com/b/lightswitch_rocks1/archive/2011/07/08/prevent-a-security-hole-with-access-control-part-i.aspx</id><published>2011-07-08T18:24:00Z</published><updated>2011-07-08T18:24:00Z</updated><content type="html">&lt;p&gt;I recently joined the Visual Studio LightSwitch team and so far have spent most of my time learning about everything that LightSwitch has to offer. With all that I&amp;rsquo;ve been learning, I thought this blog would be a perfect opportunity to share some of my new found knowledge. I can&amp;rsquo;t help but be reminded of my childhood and the lessons taught by the Saturday morning cartoon &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Schoolhouse_Rock!"&gt;Schoolhouse Rock!&lt;/a&gt;&lt;/i&gt; Granted, my blog may be missing the colorful animations, upbeat songs, and unforgettable lyrics, but I do promise to share my experiences as a LightSwitch newbie with an occasional attempt at rhyming; hence the title &lt;i&gt;LightSwitch Rocks!&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;Inspired by &lt;i&gt;Schoolhouse Rock!&lt;/i&gt; episodes with catchy titles such as &amp;ldquo;Conjunction Junction&amp;rdquo; and &amp;ldquo;My Hero, Zero&amp;rdquo;, my first blog post is appropriately called &amp;ldquo;Prevent a Security Hole with Access Control.&amp;rdquo;&amp;nbsp; This is the first post focuses on securing data on the logic tier.Scenario: Expense Report Tracker&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s begin by creating a LightSwitch project called &amp;ldquo;ExpenseReportTracker&amp;rdquo; with two entities that are used to track the status of expense reports; note that ExpenseReport has a one-to-many relationship with ExpenseItems.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Two types of users will use this application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Employees that create and save expense reports for approval&lt;/li&gt;
&lt;li&gt;Managers that approve or reject employees&amp;rsquo; expense reports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When an employee creates and saves an expense report, the report&amp;rsquo;s Status is automatically defaulted to &amp;ldquo;Pending.&amp;rdquo; The assigned Approver (e.g. manager) can then change the Status of the report to either &amp;ldquo;Approved&amp;rdquo; or &amp;ldquo;Rejected.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2870.image_5F00_7EAF7032.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/6661.image_5F00_thumb_5F00_6D7B928F.png" width="446" height="182" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/0638.image_5F00_7AE1A595.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/0310.image_5F00_thumb_5F00_0C52066E.png" width="577" height="149" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Based on the above scenario, let&amp;rsquo;s look at the security rules that we want to enforce depending on the type of user:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An employee cannot delete an expense report&lt;/li&gt;
&lt;li&gt;An employee cannot modify an expense report&amp;rsquo;s Status; this prevents employees from approving\rejecting expense reports&lt;/li&gt;
&lt;li&gt;Once a manager has set an expense report&amp;rsquo;s Status to &amp;ldquo;Approved&amp;rdquo; or &amp;ldquo;Rejected&amp;rdquo;, an employee can no longer make modifications to the report&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Creating Permissions&lt;/h3&gt;
&lt;p&gt;Since we have two types of users, there are two permissions that we need to create in the Application Properties designer; one that will be assigned to employees and another for managers.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/8540.image_5F00_19B81974.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5516.image_5F00_thumb_5F00_643F574E.png" width="593" height="208" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Enforcing Security on the Logic Tier&lt;/h2&gt;
&lt;p&gt;Now that we have permissions created for employees and managers, let&amp;rsquo;s look at how to use these permissions to enforce the security rules for our application.&lt;/p&gt;
&lt;h6&gt;&lt;span style="font-weight: bold;"&gt;Using Entity Set &amp;ldquo;Can&amp;rdquo; Methods&lt;/span&gt;&lt;/h6&gt;
&lt;p&gt;Our first security rule means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the current user is assigned to a role with ManageExpenseReportPermission, then the user &lt;span style="text-decoration: underline;"&gt;can&lt;/span&gt; delete expense reports; otherwise, the user should be prevented from deleting an expense report&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This type of rule applies to &lt;span style="text-decoration: underline;"&gt;all&lt;/span&gt; expense reports; not a particular instance of an expense report. Based on this, we can add this permission check to the ExpenseReport entity set&amp;rsquo;s CanDelete method.&amp;nbsp; This method is added by opening ExpenseReports in the entity designer and selecting &amp;ldquo;ExpenseReports_CanDelete&amp;rdquo; from the &amp;ldquo;Write Code&amp;rdquo; drop-down menu.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/5826.image_5F00_388E8D52.png"&gt;&lt;img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" border="0" alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-46-59-metablogapi/2783.image_5F00_thumb_5F00_29E3E16D.png" width="582" height="197" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the code that is written in the &amp;ldquo;ExpenseReports_CanDelete&amp;rdquo; method:&lt;/p&gt;
&lt;h6&gt;&lt;span style="background-color: #ffff00;"&gt;C#&lt;/span&gt;&lt;/h6&gt;
&lt;p&gt;&lt;span style="font-family: Courier New;" face="Courier New"&gt;&lt;span style="color: blue;"&gt;partial void &lt;/span&gt;ExpenseReports_CanDelete(&lt;span style="color: blue;"&gt;ref bool &lt;/span&gt;result) &lt;br /&gt;{ &lt;/span&gt;&lt;span style="font-family: Courier New;" face="Courier New"&gt;&lt;span style="color: green;"&gt; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;result = &lt;span style="color: blue;"&gt;this&lt;/span&gt;.Application.User.HasPermission(&lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.ManageExpenseReportPermission); &lt;br /&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;h6&gt;&lt;span style="background-color: #ffff00;"&gt;VB&lt;/span&gt;&lt;/h6&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;Private Sub &lt;/span&gt;ExpenseReports_CanDelete(&lt;span style="color: blue;"&gt;ByRef &lt;/span&gt;result &lt;span style="color: blue;"&gt;As Boolean&lt;/span&gt;)
    result = &lt;span style="color: blue;"&gt;Me&lt;/span&gt;.Application.User.HasPermission(&lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.ManageExpenseReportPermission)
&lt;span style="color: blue;"&gt;End Sub &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The benefit of using the &amp;ldquo;Can&amp;rdquo; method is two-fold; when it returns false, the user is prevented from performing the Delete operation. In addition, the application will automatically disable the Delete button on a screen that is displayed to the user.&lt;/p&gt;
&lt;p&gt;If you need to enforce security for a specific entity instance or check a data value on an entity, then you will need to instead use the save pipeline&amp;rsquo;s methods.&lt;/p&gt;
&lt;h6&gt;Using Save Pipeline Methods&lt;/h6&gt;
&lt;p&gt;Our second and third security rules require us to check data on specific entity instances, therefore we will need to use the save pipeline methods. These security rules can be interpreted as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the current user is assigned to a role with EmployeeExpenseReportPermission, the user &lt;span style="text-decoration: underline;"&gt;cannot&lt;/span&gt; modify the Status property&lt;/li&gt;
&lt;li&gt;Similarly, if the user is assigned the EmployeeExpenseReportPermission, the user &lt;span style="text-decoration: underline;"&gt;cannot&lt;/span&gt; modify an expense report that has already been approved\rejected&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These checks can be added to the ExpenseReports Updating method. This method is added by opening ExpenseReports in the entity designer and selecting &amp;ldquo;ExpenseReports_Updating&amp;rdquo; from the &amp;ldquo;Write Code&amp;rdquo; drop-down menu.&amp;nbsp; Notice that this method passes in the current entity instance as a parameter.&lt;/p&gt;
&lt;h6&gt;&lt;span style="background-color: #ffff00;"&gt;C#&lt;/span&gt;&lt;/h6&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;partial void &lt;/span&gt;ExpenseReports_Updating(&lt;span style="color: #2b91af;"&gt;ExpenseReport &lt;/span&gt;entity)
{
    &lt;span style="color: blue;"&gt;if &lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Application&lt;/span&gt;.Current.User.HasPermission(
        &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmplyeeExpenseReportPermission))
    {
        &lt;span style="color: blue;"&gt;if &lt;/span&gt;(entity.Details.Properties.Status.IsChanged)
        {
            &lt;span style="color: blue;"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(
                &lt;span style="color: #a31515;"&gt;"Permission denied: Unable to change expense report " &lt;/span&gt;+ 
                &lt;span style="color: #a31515;"&gt;"status. Report Id: " &lt;/span&gt;+ entity.ReportId);
        }

        &lt;span style="color: blue;"&gt;if &lt;/span&gt;(entity.Details.Properties.Status.Value != &lt;span style="color: #a31515;"&gt;"Pending"&lt;/span&gt;)
        {
            &lt;span style="color: blue;"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(
                &lt;span style="color: #a31515;"&gt;"Permission denied: Unable to change an expense report" &lt;/span&gt;+ 
                 &lt;span style="color: #a31515;"&gt;"that has already been 'Approved' or 'Rejected'." &lt;/span&gt;+ 
                 &lt;span style="color: #a31515;"&gt;"Report Id: " &lt;/span&gt;+ entity.ReportId);
        }
    }
}&lt;/pre&gt;
&lt;h6&gt;&lt;span style="background-color: #ffff00;"&gt;VB&lt;/span&gt;&lt;/h6&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;Private Sub &lt;/span&gt;ExpenseReports_Updating(entity &lt;span style="color: blue;"&gt;As &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ExpenseReport&lt;/span&gt;)

&lt;span style="color: blue;"&gt;If &lt;/span&gt;Application.Current.User.HasPermission(
     &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmployeeExpenseReportPermission) &lt;span style="color: blue;"&gt;Then If &lt;/span&gt;entity.Details.Properties.Status.IsChanged &lt;span style="color: blue;"&gt;Then Throw New &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(
               &lt;span style="color: #a31515;"&gt;"Permission denied: Unable to change expense " &lt;/span&gt;+
               &lt;span style="color: #a31515;"&gt;"report status. Report Id: " &lt;/span&gt;+ entity.ReportId)
          &lt;span style="color: blue;"&gt;End If If &lt;/span&gt;entity.Details.Properties.Status.Value &amp;lt;&amp;gt; &lt;span style="color: #a31515;"&gt;"Pending" &lt;/span&gt;&lt;span style="color: blue;"&gt;Then Throw New &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(
                &lt;span style="color: #a31515;"&gt;"Permission denied: Unable to change an expense " &lt;/span&gt;+
                &lt;span style="color: #a31515;"&gt;"report that has already been 'Approved' or " &lt;/span&gt;+
                &lt;span style="color: #a31515;"&gt;"'Rejected'. Report Id: " &lt;/span&gt;+ entity.ReportId)
          &lt;span style="color: blue;"&gt;End If End If End Sub &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;You may have also noticed that we have a gap in our security because an employee can still potentially modify ExpenseItems that belong to an ExpenseReport that has already been approved\rejected. To bridge this gap, we need to add the following code to the &amp;ldquo;ExpenseItems_Inserting&amp;rdquo;, &amp;ldquo;ExpenseItems_Updating&amp;rdquo;, and &amp;ldquo;ExpenseItems_Deleting&amp;rdquo; methods.&amp;nbsp; These methods are added via the &amp;ldquo;Write Code&amp;rdquo; drop-down menu that is available in the entity designer for ExpenseItems.&lt;/p&gt;
&lt;h6&gt;&lt;/h6&gt;
&lt;p&gt;&lt;span style="background-color: #ffff00;"&gt;&lt;strong&gt;C#&lt;/strong&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="background-color: #ffffff;"&gt;&lt;span style="color: blue;"&gt;partial void &lt;/span&gt;ExpenseItems_Inserting(&lt;span style="color: #2b91af;"&gt;ExpenseItem &lt;/span&gt;entity) { &lt;span style="color: blue;"&gt;if &lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Application&lt;/span&gt;.Current.User.HasPermission( &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmplyeeExpenseReportPermission) &amp;amp;&amp;amp; entity.ExpenseReport.Status != &lt;span style="color: #a31515;"&gt;"Pending"&lt;/span&gt;) { &lt;span style="color: blue;"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Permission Denied: Unable to modify " &lt;/span&gt;+ &lt;span style="color: #a31515;"&gt;"expense report that has already been 'Approved' or " &lt;/span&gt;+ &lt;span style="color: #a31515;"&gt;"'Rejected'. Report id: " &lt;/span&gt;+ entity.ExpenseReport.ReportId); } } &lt;span style="color: blue;"&gt;partial void &lt;/span&gt;ExpenseItems_Updating(&lt;span style="color: #2b91af;"&gt;ExpenseItem &lt;/span&gt;entity) { &lt;span style="color: blue;"&gt;if &lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Application&lt;/span&gt;.Current.User.HasPermission( &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmplyeeExpenseReportPermission) &amp;amp;&amp;amp; entity.ExpenseReport.Status != &lt;span style="color: #a31515;"&gt;"Pending"&lt;/span&gt;) { &lt;span style="color: blue;"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Permission Denied: Unable to modify " &lt;/span&gt;+ &lt;span style="color: #a31515;"&gt;"expense report that has already been 'Approved' or " &lt;/span&gt;+ &lt;span style="color: #a31515;"&gt;"'Rejected'. Expense report id:" &lt;/span&gt;+ entity.ExpenseReport.ReportId); } } &lt;span style="color: blue;"&gt;partial void &lt;/span&gt;ExpenseItems_Deleting(&lt;span style="color: #2b91af;"&gt;ExpenseItem &lt;/span&gt;entity) { &lt;span style="color: blue;"&gt;if &lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Application&lt;/span&gt;.Current.User.HasPermission( &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmplyeeExpenseReportPermission) &amp;amp;&amp;amp; entity.ExpenseReport.Status != &lt;span style="color: #a31515;"&gt;"Pending"&lt;/span&gt;) { &lt;span style="color: blue;"&gt;throw new &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Unable to modify expense report that has " &lt;/span&gt;+ &lt;span style="color: #a31515;"&gt;"already been 'Approved' or 'Rejected'. Expense report id: " &lt;/span&gt;+ entity.ExpenseReport.ReportId); } }&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h6&gt;&lt;span style="background-color: #ffff00;"&gt;VB&lt;/span&gt;&amp;nbsp;&lt;/h6&gt;
&lt;pre class="code"&gt;&lt;span style="color: blue;"&gt;Private Sub &lt;/span&gt;ExpenseItems_Inserting(entity &lt;span style="color: blue;"&gt;As &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ExpenseItem&lt;/span&gt;)

     &lt;span style="color: blue;"&gt;If &lt;/span&gt;Application.Current.User.HasPermission(
        &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmployeeExpenseReportPermission) &lt;span style="color: blue;"&gt;And &lt;/span&gt;entity.ExpenseReport.ReportId &lt;span style="color: blue;"&gt;Then Throw New &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Permission Denied: Unable to modify " &lt;/span&gt;+
            &lt;span style="color: #a31515;"&gt;"expense report that has already been 'Approved' or " &lt;/span&gt;+
            &lt;span style="color: #a31515;"&gt;"'Rejected'. Report id: " &lt;/span&gt;+ entity.ExpenseReport.ReportId)
     &lt;span style="color: blue;"&gt;End If End Sub Private Sub &lt;/span&gt;ExpenseItems_Updating(entity &lt;span style="color: blue;"&gt;As &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ExpenseItem&lt;/span&gt;)

     &lt;span style="color: blue;"&gt;If &lt;/span&gt;Application.Current.User.HasPermission(
        &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmployeeExpenseReportPermission) &lt;span style="color: blue;"&gt;And &lt;/span&gt;entity.ExpenseReport.ReportId &lt;span style="color: blue;"&gt;Then Throw New &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Permission Denied: Unable to modify " &lt;/span&gt;+
              &lt;span style="color: #a31515;"&gt;"expense report that has already been 'Approved' or " &lt;/span&gt;+
              &lt;span style="color: #a31515;"&gt;"'Rejected'. Report id: " &lt;/span&gt;+ entity.ExpenseReport.ReportId)
     &lt;span style="color: blue;"&gt;End If End Sub Private Sub &lt;/span&gt;ExpenseItems_Deleting(entity &lt;span style="color: blue;"&gt;As &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;ExpenseItem&lt;/span&gt;)

      &lt;span style="color: blue;"&gt;If &lt;/span&gt;Application.Current.User.HasPermission(
         &lt;span style="color: #2b91af;"&gt;Permissions&lt;/span&gt;.EmployeeExpenseReportPermission) &lt;span style="color: blue;"&gt;And &lt;/span&gt;entity.ExpenseReport.ReportId &lt;span style="color: blue;"&gt;Then Throw New &lt;/span&gt;&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Permission Denied: Unable to modify " &lt;/span&gt;+
             &lt;span style="color: #a31515;"&gt;"expense report that has already been 'Approved' or " &lt;/span&gt;+
             &lt;span style="color: #a31515;"&gt;"'Rejected'. Report id: " &lt;/span&gt;+ entity.ExpenseReport.ReportId)

      &lt;span style="color: blue;"&gt;End If &lt;/span&gt;&lt;span style="color: blue;"&gt;End Sub &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This check prevents employees from inserting, updating, and deleting ExpenseItems for a report that already has the Status set to either &amp;ldquo;Approved&amp;rdquo; or &amp;ldquo;Rejected&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;It is important to note that when an exception is thrown in the save pipeline methods that the changes are rolled back and the user is displayed a dialog box with the specified exception message.&lt;/p&gt;
&lt;h5&gt;Summary&lt;/h5&gt;
&lt;p&gt;The first step to properly securing an application is to secure your data on the logic tier by adding permission checks.&amp;nbsp; This post has shown how to do this by adding permission checks to both the entity set &amp;ldquo;Can&amp;rdquo; methods and save pipeline methods.&lt;/p&gt;
&lt;p&gt;Next time I will extend&amp;nbsp; the &amp;ldquo;Expense Report Tracker&amp;rdquo; scenario to show how you can customize the appearance of screens according to the underlying security permissions for the user.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Thanks for joining me for my first blog post!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=10184680" width="1" height="1"&gt;</content><author><name>Nicole Haugen</name><uri>http://blogs.msdn.com/nicolehaugen79_4000_hotmail.com/ProfileUrlRedirect.ashx</uri></author><category term="Nicole Haugen" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Nicole+Haugen/" /><category term="Silverlight" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Silverlight/" /><category term="LightSwitch" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/LightSwitch/" /><category term="Access Control" scheme="http://blogs.msdn.com/b/lightswitch_rocks1/archive/tags/Access+Control/" /></entry></feed>