ASP.NET Dynamic Data, adding ‘Required Field’ asterisks or other notation to control labels

So this is a pretty straightforward concern, but I wanted to add validation notation to a FieldTemplate’s Label, and not necessarily its control. In ASP.NET’s dynamic data, this isn’t straightforward. What I found is that using Entity Templates is better than editing individual Field Templates. 

Go into your dynamic data directory and open Default_Edit.ascx and Default_Insert.ascx files. Add a Label to each, like so. This label represents our required field token.

<asp:Label OnInit=”Required_Init” runat=”server” Text=” *” Visible=”false” />

Now, you’ll notice this control has an OnInit Handler. Basically, these controls IDs are not available in the codebehind based on the draw order, from what I can tell. So you can set their values when they are drawn, not on a global control-wide event, but on the individual control’s events.

protected void Required_Init(object sender, EventArgs e)
	{

	if (currentColumn.TypeCode != TypeCode.Boolean)
			((Label)sender).Visible = currentColumn.IsRequired;
	}

Basically, you create a simple event listener that will hide or show the control you just added based on the required-ness of the field. Note that I do not set the label to visible if the column is bound to a Boolean; this is because Booleans render as checkboxes and the idea of ‘requiredness’ sort of doesn’t fit… if you don’t check the checkbox, you are still submitting the field with a value of ‘false’, so required does not apply.

Adding Swipe functionality to WPF Applications

As part of a kiosk application written in WPF, the client wanted ‘Swipe’-like functionality similar to many touch-enabled smartphones. It’s actually not that hard in .NET 4 and WPF. 

First, add a property to your page/control that keeps track of the Touch that the user has initiated to start the swipe event:

protected TouchPoint TouchStart;

In the codebehind of the Page or Control you’re building, add the following handlers:

 

public BasePage()

{

this.TouchDown += new EventHandler<TouchEventArgs>(BasePage_TouchDown);

this.TouchMove += new EventHandler<TouchEventArgs>(BasePage_TouchMove);            

}

These handlers help detect when a user has pressed down and moved his/her finger over your page or control.

Next, handle the initial Touch event that triggers the swipe:

 

void BasePage_TouchDown(object sender, TouchEventArgs e)

{            TouchStart = e.GetTouchPoint(this); }

Finally, handle the movement aspect of the touch. If the movement exceeds some threshhold; then we consider it a swipe and execute whatever code we want to do (Navigation, animation, etc)

Here, ‘AlreadySwiped’ is just a flag property so we don’t execute the same task multiple times if the swipe exceeds our threshhold more than once. You are responsible for resetting it after you do your on-swiped code. Also, I used 200 pixels as the swipe threshhold, but you may want a bigger/smaller value. You may also want to consider percentages of X here instead of actual pixels.

void BasePage_TouchMove(object sender, TouchEventArgs e)

{

            if (!AlreadySwiped)

            {                

                var Touch = e.GetTouchPoint(this);

                //right now a swipe is 200 pixels 

 

                //Swipe Left

                if (TouchStart != null && Touch.Position.X > (TouchStart.Position.X + 200))

                {

                    RunMyCustomCode();

                    AlreadySwiped = true;

                }

 

                //Swipe Right

                if (TouchStart != null && Touch.Position.X < (TouchStart.Position.X – 200))

                {

                     RunMyCustomCodeSwipeRight();

                    AlreadySwiped = true;

                }

            }

            e.Handled = true;

}

This should be straightforward but send me a message if you have any questions.

 

 

ASP.NET Dynamic Data, Changing the Many-To-Many fieldtemplate to not display links

By default, the Entity Data Model version of Dynamic Data allows you to use a Many-To-Many fieldtemplate user control, which on display shows you a nice list of links for each related entity. However, in some instances you might not want to show links. Perhaps you want to show plain text, or maybe a custom control?

Diving into the code for the Many-To-Many field template, its not clear exactly how the binding is happening. Here is the ASPX file for the Many To Many control, before editing:

<asp:Repeater ID=”Repeater1″ runat=”server”>

<ItemTemplate><asp:DynamicHyperLink runat=”server”></asp:DynamicHyperLink></ItemTemplate></asp:Repeater>

Not very helpful, right? The normal controls have FieldValueString or some other property from the control available to them to bind. Here, we are in a repeater so one property won’t do, we need to peer into the collection or item from the collection at binding time.

The other problem is we can’t just expect to know the property name. The property name(s) may be different depending on which Many-To-Many relationship we are dealing with. So we need to know a little about how Dynamic Data works to pull this off.

The first thing we can do is replace our Dynamic Hyperlink (which seems to be smart enough at bind-time to pick up the proper fields) with a Literal or some other control, like so: 

<asp:Literal runat=”server” Text=”<%# GetDisplayString(Container.DataItem) %> />

 cool? Now we have a literal instead of a hyperlink, and we are making a call to a function that we need to define. That function will take the individual item we’ve bound, and figure out what value to display. Now lets look at the function we need to make in the code behind:   protected string GetDisplayString(object value){   MetaTable actualTable = MetaTable.GetTable(value.GetType()); return actualTable.GetDisplayString(value); }

 

 This function is doing two things: It is getting the MetaTable of the object we have by inferring it from the Type of object we are binding to. Then, once it knows the MetaTable it can figure out what the Display Name should be for that field. The Display Name is taken either from the ‘TableName’ Data Annotation  , or if one does not exist, it grabs the first string it can find from the table.

Voila! No Links anymore. That’s all you need, and now you might know a little about how Dynamic Data works under the hood.

Missing DataContext, "The custom tool ‘MSLinqToSQLGenerator’ failed. "

While working on a project with a LinqToSQL Classes object (.dbml), sometimes your dbml file will get hosed when you remove/add/modify some part of the data model. At first, my error was “The custom tool ‘MSLinqToSQLGenerator’ failed.” , indicating that the LinqToSQL custom tool was failing. Oddly, what would happen is the code would end up deleting the .designer.cs file … I googled around and found some other people who had the same issue, which for me was resolved taking the following steps:

  1. On your .dbml file, drill into the file and, if you are not using a partial class declaration, delete the <modelname>.cs file that’s generated. 
  2. Right-click the .dbml file and choose ‘Run Custom Tool’.

This restores the <modelname>.designer.cs file, but that’s only half the battle. For me, when generating the .designer.cs file, the Custom Tool no longer flagged that file as ‘compile’ in the build process, so while the ‘custom tool’ error was gone, my other ‘missing data context’ errors were still present. You then have to right-click on the <modelname>.designer.cs file, go to Properties, and choose ‘compile’ as the build action. Otherwise, you will continue to have missing <modename>DataContext errors .

Hope this helps someone! I was stumped.

Excel Automation & Windows Server 2008 x64

So I admit it, I have gone against Microsoft’s best practices and used Microsoft Excel on a server and had my web-based code call the Interop COM Library in order to generate Excel files. Sorry, but it works, and the code is managed and free. I won’t lie, I love using Microsoft.Office.Interop.Excel. So suck it.

But in migrating one of our servers to a new environment, we found we could no longer generate excel files. Our code was generating the following error messages under our new environment.

Working config: Microsoft Excel Enterprise 2007 + Windows Server 2008 x64 edition + .NET 4.0 web application

 

Server Error in ‘/excel’ Application.


Retrieving the COM class factory for component with CLSID {00024500-0000-0000-C000-000000000046} failed due to the following error: 80070005.

This error is basically saying that the IIS / ASP.NET framework does not have permission under its current user to run/access COM Objects.

Following the instructions here http://www.computerperformance.co.uk/Logon/code/code_80070005.htm Led me to a solution. Using DCOMCNFG you can set COM permissions. However, instead of just setting COM permissions on the ‘Microsoft Excel Application’, I needed to set permissions for the entire computer. The linked article has you setting permissions for ‘Everyone’ but that’s not necessary. You only need to set permissions for NETWORK SERVICE user. 

Originally, I had followed the steps located here: http://blog.crowe.co.nz/archive/2006/03/02/589.aspx … those steps have you set permissions to NETWORK SERVICE but only on the Excel Application. For some reason, that wasn’t enough on my environment, I needed to set it on the entire ‘My Computer’ and not the individual app. 

OK, so I set up permissions, but then I was getting a totally different error, one that didn’t jive at all:

“Microsoft
Office Excel cannot open or save any more documents because there is not
enough available memory or disk space.

• To make
more memory available, close workbooks or programs you no longer need.

• To free
disk space, delete files you no longer need from the disk you are saving
to.”

This is of course false. My machine had plenty of space. So what gives?

This is the hardest part to grok, IMHO. This error will NOT occur in Windows Server 2008 32 bit edition (x86). Why not? Because the Folder Structure is different for a user in x64 edition. Excel, when opened, actually tries to create some temporary files or other data when it loads. If it does not have the ability to write to the disk (either because the disk is actually full, or in our case, because that folder is not something we can write to due to security setup), then the disk error is the default message shuttled back to the user. Here are the write locations

C:WindowsSysWOW64configsystemprofileDesktop (x64, does not exist by default)

C:WindowsSystem32configsystemprofileDesktop (x86, exists by default and is writeable)

http://social.msdn.microsoft.com/Forums/en-US/innovateonoffice/thread/b81a3c4e-62db-488b-af06-44421818ef91 has more on this issue. Basically, to get this to work, take two steps: Create C:WindowsSysWOW64configsystemprofileDesktop and give C:WindowsSysWOW64configsystemprofile folder write access to ‘Everyone’. This will allow excel to proceed past this error and hopefully start automating files for you.

Finally, I was getting one last error after doing this step:

Service cannot be started.
System.Runtime.InteropServices.COMException (0x800A03EC): Microsoft
Office Excel cannot access the file ‘c:temptest.xls’. There are
several possible reasons:

• The file name or path does not exist.
• The file is being used
by another program.
• The workbook you are trying to save has the
same name as a currently open workbook.

This is because the folder I was trying to write to was not allowed full-control rights by NETWORK SERVICE. If you app writes excel files to a directory, that directory must be full-control permissioned to NETWORK SERVICE.

ONE OTHER THING: If you are running an OFFICE TRIAL VERSION and you have not entered a license key, your app might hang and never load anything. This is because the COM Object actually spawns a modal dialog for a license key and your code will wait there for a user who will never come to add a license key. So, be sure if you’re automating excel that you ONLY using a registered version and not a 30 day trial or unlicensed version. 

 

Back in the .NET Game; Plus

So I took a new job which has me writing C# code again, which is great! A lot of new developments have happened in ASP.NET land since I’ve been gone, such as MVC framework, ASP.NET 3.5, etc. However, I’ve been working to keep up with them and I’m excited about what the future holds.

The last few days I’ve been working on a Flex + Sharepoint project for my employer. Sharepoint has a robust set of web services, but accessing them can be a bit confusing. For the method ‘GetListItems’, accessing all items from a list can be pretty easy… the http://sharepointserver/_vti_bin/Lists.asmx service endpoint provides you with the ability to getListItems by listName …however, if you want to do more than just grab one list item, you might be in for a hurting. Getting a specific subset of lists means you have to pass in a complex parameter, like viewFields … The viewFields parameter of GetListItems is not a simple type like a string or number. Instead, its an XML subtype and you’re required to pass in a specific format of XML within this node. If you pass XML that sharepoint does not expect, you’ll see something like ‘ ViewFields is missing or invalid’ … Normally people consume web services with generated code from ASP.NET… When I found myself in Flex, however, the generated tools fell a little short.

Problem 1 is that Flex WebServices libraries by default append a namespace to each node that they send in their Soap Bodies. Usually the namespace is “tns:” … that’s fine, but it was unclear to me if the complex XML children parameters of the webservice needed this namespace too… turns out, they do not.

<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap-env:body>
    <tns:getlistitems xmlns:tns="http://schemas.microsoft.com/sharepoint/soap/">
      <tns:listname>Regions</tns:listname>
      <tns:viewfields>
        <viewfields>
          <fieldref name="LinkTitle">
        </fieldref>
      </viewfields>
      <tns:rowlimit>2</tns:rowlimit>
      <tns:queryoptions>
        <queryoptions>
          <includemandatorycolumns>FALSE</includemandatorycolumns>
          <dateinutc>TRUE</dateinutc>
        </queryoptions>
      </tns:queryoptions>
    </tns:viewfields>
  </tns:getlistitems>
</soap-env:body></soap-env:envelope>

(note the lack of ‘tns:’ in the ‘queryoptions’ and ‘viewfields’ parameters)

Problem 2 is lack of examples of actual web requests of Sharepoint services. Which normally you wouldn’t need if you’re consuming generated code from Visual Studio. But if you’re writing custom webservice wrappers, or doing anything nonstandard, then you need to have your hands dirty and understand what’s going on at the transport level. For a while I didn’t realize that the viewFields parameter needed , as its root child element, a viewFields element… the examples page was unclear; and every other code example had me writing ASP,NET go-between layers. That’s not what I want, I want my Flex movie talking right to sharepoint. Anyways, what made this whole process way easier was Flash Builder 4, which generates code for you based on a WSDL; a lot like ASP.NET does. So you end up with something like this:

 

var viewFields:XML = <ViewFields><FieldRef Name="LinkTitle" /></ViewFields>;
 var queryOptions:XML =
                    <QueryOptions>
                       <IncludeMandatoryColumns>FALSE
                          </IncludeMandatoryColumns>
                       <DateInUtc>TRUE</DateInUtc>
                    </QueryOptions>;
           
var myLists:Lists = new Lists();
                               
myLists.addEventListener(FaultEvent.FAULT, handleFaults);
myLists.addEventListener(ResultEvent.RESULT, RegionsResult);
myLists.GetListItems("Regions",null, null, viewFields, "2", queryOptions, null);

Makes sense now, but if you’re coming in green, Sharepoint connectivity can be a pain without raw XML examples!

StackOverFlow in mscordlib.dll and SiteMap Providers

Word to the wise, unless you want to spend hours tracking down idiotic Stack Overflows, check your Sitemap files in ASP.NET. Each sitemap node can contain a ‘Provider’ attribute. This is designed so that you can set up several sitemaps, and have a master sitemap file pull submenuitems from seperate sitemap files (or databases, depending on your sitemap provider configuration, and whether you rolled your own. However, if you mistakenly point a sitemap provider node to the same provider that references the sitemap file you’re in, you’ll get a stack overflow error. This was tricky because its actually the webserver that blows the stack, so you can’t debug or trace your way out of it. What a fool I’ve been :)

asp:menu control and SiteMap, ‘Selected’ Item must match exact url?

 So I am back into making .NET websites… and I love the web.sitemap feature of .NET 2.0+ However, I like my web folder structure to be semantic. This means that instead of clunky files with extensions, I like to have a directory for every portion of the site. Example:

http://www.website.com/products/, http://www.website.com/aboutus/

And then every folder has a Default.aspx … but the problem with this is that the sitemap, when connected to an ASP.NET Menu control, is that the selected page is only recognized if the page name is included… so my sitemap has to be /products/Default.aspx , instead of just /products/… that’s a bummer, because then I lose my semantic ‘feel’.

Anyone have any ideas on how to modify this? I’d prefer not to override the Menu control if I don’t have to.

Update: So I dug a little deeper and found a solution. First, in your web.sitemap file, keep all the URLs to be exact, including the Default.aspx file. Then, in your menu control, add an onDataBound event handler as such:

    protected void SubMenu_DataBound(object sender, EventArgs e)

    {

        foreach (MenuItem Mi in ((Menu)sender).Items)

        {

            //Trim default.aspx from Menu Item URL; this is for SEO

            Mi.NavigateUrl = Mi.NavigateUrl.Replace(“Default.aspx”, “”);

        }

    }

 

 

GamerServices Game Components don’t respond!

So I’ve been re-tooling my demo-game in XNA to take advantage of XNA 2.0 enhancements. So one thing I noticed is that my very simple code that I lifted from NetRumble project wasn’t working in my project. It was a simple sign-in invocation:

if (!Guide.IsVisible)

{

Guide.ShowSignIn(1, false);

}


It was displaying, but not responding to input. (although my underlying components were responding to input.)


I had included the addition of the proper component in the Game’s constructor:


Components.Add(new GamerServicesComponent(this));


but still no luck. Finally, even though it wasn’t in the NetRumble game, I found in the MSDN documentation that “However, in some cases a program might not use the XNA Framework application model or component infrastructure.” Whatever. I thought I was doing everything right. But turns out I needed to manually ‘prime the pump’, so to speak.


http://msdn2.microsoft.com/en-us/library/bb975692.aspx


 Adding the following line in the Game’s Update method:


GamerServicesDispatcher.Update();


 Solved my problem. Unsure what I did to hose this component though. Or automatically adding components. Probably somewhere deep in my code I have the Game Components object do a .Clear or something

Check intersection of two date ranges in SQL

Sometimes we have objects which have timespans in our database, such as valid dates for coupons, or say active dates of a sale, or trigger, or some other event. in searching through these, we may want to give a user the ability to see all of these objects which were ‘active’, or whose timespan intersects  a user’s search criteria. So the user gives a set of dates, and we want to see if any date inside the user’s date at all also exists inside the date that the object in our DB was active. The following pseudo-code should hash out how I solved this problem. 


AND( 
   (userselected_start_date <= dbobject_end_date AND userselected_end_date >= dbobject_start_date )
   OR
   (userselected_start_date <= dbobject_start_date AND userselected_end_date >= dbobject_end_date)
   OR
   ((userselected_start_date <= dbobject_end_date AND userselected_start_date >= dbobject_start_date) OR


   (userselected_end_date >= dbobject_start_date AND userselected_end_date <= dbobject_end_date))
   )


These three OR statements essentially fill the three criteria about the user’s timespan and how it relates to the timespan in the database. There are four possibilities for the set theory relationship between the date ranges.



  1. The date ranges share no common dates. This means the sets are disjoint, and in the above where clause, the rows would not be returned

  2. The date range the user selects is a superset of the database range

  3. The date range the user selects is a subset of the database range

  4. The date range the user selects has some members, but not all members, which are also found in the date range in our database

This is a bit obscure, but in writing web reports this has come up a few times. Hope it helps someone.


Update:


Ruud Campsteijn points out that it is much easier to check if dates don’t intersect, and invert the results.


AND NOT (daterange1_startdate > daterange2_end_date OR daterange1_endate < daterange2_startdate)

Just another BloggingAbout.NET site