Thursday, November 11, 2010

Getting Current User information in Silverlight 4

Let’s assume for a Silverlight application. You may be wondering where to find out who the current user is. In ASP.NET there is a User property on the Page object (also other places such as the HttpContext.Current), but where is that in Silverlight 4 (not in early versions that I am aware of). The answer is the WebContext.

I think the WebContext was introduced in Silverlight 4.You The WebContext is created in the constructor of the App class that is in the App.xaml.cs file. If it isn’t you may be using a different type of Silverlight 4 project than the Silverlight Business Application or Silverlight Navigation Application. If you app doesn’t have this, I am assuming you can add it. Just create on of these projects and copy what is done there.

Among other things, the WebContext has a User property. This gives you what acts like what you may expect if you are accustomed to ASP.NET. For example, it has a Roles property to see what roles the user in. It has a IsUserInRole() method to see if a user is in a particular role. It has a Name property that gives you the username.

The WebContext is accessible from code by using WebContext and is also added to the Application Resources in the Application_Startup method which makes it accessible via XAML. To show the current username using XAML you would do something like the following:

<TextBlock x:Name="CurrentUser" Text="{Binding Current.User.Name, Source={StaticResource WebContext}}" />

Using XAML is really great because as Current.User changes from null to some value when the user logs in or Windows Authentication logs them in automatically, the TextBlock will be notified and display the change.

. The same is NOT true if you use code that you may write in ASP.NET to set the value. For example:

Assume you XAML is now defined like this:

<TextBlock x:Name="CurrentUser" />

You might be tempted to write the following line of code

CurrentUser.Text = WebContext.Current.User.Name;

The problem is that WebContext.Current.User may be null initially AND the biggest problem is that you won’t be able to pick up the Name since it may NOT be set yet. Really what we want is to using Bindings which notify the other side of the binding when the value changes. This means that initially we would get no username, but as soon as it is loaded we would be notified that there is a new value and we can show it.

The code is a little more complex than above, but not really too bad. Basically, we are trying to do what we did in XAML in the first example, but do it in code. Here is all you have to do:

CurrentUser.SetBinding(TextBlock.TextProperty, WebContext.Current.CreateOneWayBinding("User.Name"));

Now we the CurrentUser textblock will always display the current value of WebContext.Current.User.Name even as it changes.

Wednesday, November 3, 2010

Getting the Action or DynamicDataRoute from a DynamicData page

If you are working in a Dynamic Data web application sometimes you may need to know what the Action (List, Details, Edit, Insert) is. The Action is just a string and is set in the Global.asax.cs in the RegisterRoutes() method that is called on application startup. Actually, if you look at each route that is added, the object being added is a DynamicDataRoute object. This is the object we eventually want to access since it has our Action property.

When you are on a PageTemplate, a CustomPage, EntityTemplate, or a UserControl that you use in one of the previous items you have access to a class called DynamicDataRouteHandler. It has a static method called GetRequestContext() which has a RouteData property. This gives us the RouteData object which has a Route property which is of type BaseRoute. Remember, we need to get an instance of the DynamicDataRoute. As it turns out DynamicDataRoute is a subclass of Route which is a subclass of BaseRoute. So, all we have to do is cast the BaseRoute object we now have to a DynamicDataRoute and we now have access to the Action property.

I guess that is a lot of explaining for a few lines of code :) Here is the code.

RouteData route = DynamicDataRouteHandler.GetRequestContext(Context).RouteData;
DynamicDataRoute ddRouteData = route.Route as DynamicDataRoute;
string action = ddRouteData.Action;

Tuesday, November 2, 2010

Adding an item to the ValidationSummary programmatically

In ASP.NET, the ValidationSummary can be used to display errors to the end user. They can specific to a field or just be entity specific, etc. In general, field specific validation shows up next to a control that it is validating (assuming you put the validators next to it). But what about validation that happens in a Domain Service Class or your Custom BLL for example? These exceptions will by default be caught by the application and show as a nasty error to the user, or go to the error page. This is hardly the desired behavior for a validation error.

First I like to change the default behavior of bubbling up to the application to be caught to being handled at the button or page level. To do this I put a try-catch in my button action or other applicable event that you can tap into. In the catch, it would be ideal to add a custom error message to the ValidationSummary. How do we do that though?

Thankfully, it is quite easy to add an item to the ValidationSummary. The key is that the Page has a Validators property that all validators are automatically added to when you put them on your .aspx page. The problem is that we don’t have a CustomValidator.

Thus we need to create a CustomValidator, but what a pain really since we only want to use it when we actually have an exception in our BLL. My solution is to create method to encapsulate the logic to create a new CustomValidator and add it to the Page’s Validators collection. So that it can easily be accessed on any page, I have implemented it as an Extension to the Page class. Below is the code to do so.

namespace MyExtensions
{
    public static class PageExtensions
    {
        public static void AddValidationSummaryItem(this Page page, string errorMessage)
        {
            var validator = new CustomValidator();
            validator.IsValid = false;
            validator.ErrorMessage = errorMessage;
            page.Validators.Add(validator);
        }
    }
}

To use this method just put the using MyExtensions; statement at the top of your code-behind of the page that you want to use it on. Then you can do the following:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    try
    {
        // do some stuff like call my BLL that may throw an exception
    }
    catch (Exception ex)
    {
        if (ex.Message == "Some key string I want to handle")
        {
            Page.AddValidationSummaryItem("Password must be at least 6 characters in length.");
        }
        else
        {
            throw ex;
        }
    }
}

WARNING: Be careful with what you display to the end user. You should never catch an exception and display the Message directly to the user. It could have information that a hacker can use to compromise your application.

UPDATE 5/5/2011:

You may notice that there are times the above method does not work as expected. In particular you may notice that the error message does not show in the ValidationSummary control as you expected even though the Page.IsValid is false (as expected). The problem is likely that you have specified the ValidationGroup on the ValidationSummary control. This is a common issue when using validators and ValiationSummary controls. They must have the same value for ValidationGroup in order to tie them together. When using DynamicData templates the ValidationGroup is NOT set so the above method works great. However, in other situations such as a simple form or maybe the FormView the ValidationGroup property may be specified depending on how your code was generated or if you changed the defaults.

To help with that issue, I have created another version (overloaded method) of this method that takes one addition parameter called validationGroup.

public static void AddValidationSummaryItem(this Page page, string errorMessage, string validationGroup)
{
    var validator = new CustomValidator();
    validator.IsValid = false;
    validator.ErrorMessage = errorMessage;
    validator.ValidationGroup = validationGroup;
    page.Validators.Add(validator);
}

WARNING: If you call Page.Validate() or Page.Validate(“your validation group here”) after the above call, the validator will be reset to valid since we hardcoded the IsValid value and the default is valid.

Tuesday, October 19, 2010

Returning the row index using LINQ

Imagine you have a contest and each entry has a some points that they were awarded. To show an ordered list of them is easy enough. Something like the following will return the names and the related points.

Entries
.Select(entry => new {
entry.Name,
entry.TotalPoints,
}
)
.OrderBy (o => o.TotalPoints)

Now what if you wanted to show the rank (1st, 2nd, 3rd, etc) for each entry. So basically now we have three columns in the results: Rank, Name, TotalPoints. How would we do this?

The answer is hidden in the LINQ to Objects specially overloaded Select method that is available only when you use the Lambda syntax where if you specify a second parameter it will put the row index in it. Here is that same query, but with the Rank column added.

Entries.ToList()
.Select((entry, index) => new {
entry.Name,
entry.TotalPoints,
Rank = index + 1
}
)
.OrderBy (o => o.TotalPoints)


Notice how we used the ToList() to convert the query to a List first. This is critical as you will get a runtime error otherwise.

FYI, the error is: Unsupported overload used for query operator 'Select'.

Also note, the name index is not important. It is the order in the Select method that is important. The index is zero based, and I wanted to show 1 based Rankings so I added one to the index to get the Rank.

Using GroupBy with LINQ

I love LINQ, but sometimes the syntax can be a little strange. In particular, I find the group by syntax to be a little weird, but not too bad once I broke it down.

For this example, let’s assume we have a person table. The person table has a column called Score and has some other fields that don’t really matter for this example. The related table is a Gender table. It has one field of importance and that is the Name field. The two rows in this table are Male and Female. There is a foreign key in the Person table that points to the Gender table. Think of it this way. The person table is the main table, and there could be a drop down list to select the gender for the person.

With that in mind, we want to know what the total score for Males and Females. We want to do this using a group by. The results will be two columns: Gender and Score.

Here is an example of the output that we desire.

Gender Score
Female 2013
Male 1923

Here is the lamdba based LINQ query we would need to do this.

   People
   .GroupBy (e => new {Gender = e.Gender.Name} )
   .Select (byGenderGroup =>
         new 
         {
            Gender = byGenderGroup.Key.Gender,
            Score = byGenderGroup.Sum (t => t.Score)
         }
   );

If we take this line by line we will see that this really isn’t so different from SQL that would be generated. Here is the SQL

   SELECT SUM([t0].[Score]) AS [Score], [t1].[Name] AS [Gender]
FROM [Person] AS [t0]
INNER JOIN [Gender] AS [t1] ON [t1].[ID] = [t0].[GenderID]
GROUP BY [t1].[Name]

Let’s go line by line of the LINQ code.

People is the main table we are working with

GroupBy creates an anonymous type (that way we can easily add additional columns to group by). In this case we group by the Gender.Name just like the last line of the SQL statement.

The Select lines create another anonymous type so that we can select just the columns we want to return. Notice that byGenderGroup doesn’t have a property called Gender. Since byGenderGroup doesn’t represent a person record and actually represents the grouped results, we can access any of the columns that we have grouped by in the above GroupBy line. In this case, Key collection only gives us one property, and that is Gender. The byGenderGroup does have many other methods that are available though. One example is the sum method. In general byGenderGroup has all the aggregate functions you would have in SQL.

FYI, you can also do this without using lamdba expressions, though I personally don’t like the syntax and find it confusing.

var results = from p in People group p by new {Gender = p.Gender.Name} into byGenderGroup
select new {byGenderGroup.Key.Gender, Score = byGenderGroup.Sum (t => t.Score)};

The choice is yours.

Monday, October 18, 2010

SharePoint users can no longer upload files larger than 25 MB after moving from Windows Server 2003 to 2008

I can’t take credit for this one, but it is worth a post.

Problem:

After moving SharePoint from Windows Server 2003 to Server 2008, users can no longer upload files larger than 25 MB. 

Explanation:

This is by design.  SharePoint, by default, restricts file uploads greater than 50 MB.  But IIS 7, by default, restricts file uploads greater than 25 MB.  When this threshold is reached the user gets a 404.13 error.  Of course since all users have "friendly" errors turned on, it is hard to tell why the file didn't upload.  One user even got a Google "Oops" page.

Solution:

Edit the web.config file for each virtual directory and force the threshold to be a little bigger than SharePoint's threshold.  If the threshold is hit, you want the SharePoint error to appear and not IIS's error.

   1: Replace:
   2: <system.net>
   3: <defaultProxy>
   4: <proxy autoDetect="true" />
   5: </defaultProxy>
   6: </system.net>
   7: </configuration>
   8:  
   9: With:
  10: <system.net>
  11: <defaultProxy>
  12: <proxy autoDetect="true" />
  13: </defaultProxy>
  14: </system.net>
  15: <system.webServer>
  16: <security>
  17: <requestFiltering>
  18: <requestLimits maxAllowedContentLength="52428800"/>
  19: </requestFiltering>
  20: </security>
  21: </system.webServer>
  22: </configuration>

The change is instant.  No closing of the browser or restarting of anything is needed.

KB Resource:

http://support.microsoft.com/kb/944981

Working with Dynamic Data Controls: Finding, Set Value, Get Value

Once you start working with ASP.NET, FormView, and the DynamicData controls you will soon learn that it isn’t as convenient to get and set values as you might like. You may also want to find controls not by their name, but by the column / property that they are bound to in the ADO.NET Entity Model.

I have put together some extensions to the Control class that make doing all these things much easier. All you have to do is create a class in your project called ControlExtensions. Copy and paste the code below into it. Change the namespace as needed. Then on the page you want to use it, just include the namespace. Then when you look at the methods on any control you will see the methods below. I have tested the code below with a FormView and also with DynamicControls on a User Control  that is then on a FormView. In both cases, the code works well.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.DynamicData;
using System.ComponentModel;

namespace DistiPromo.Helpers
{
    public static class ControlExtensions
    {

        /// <summary>
        /// This will find the Dynamic Data control for the specified column (name from Entity model)
        /// </summary>
        /// <param name="control">the control (such as FormView or UserControl) that directly contains the control you are looking for</param>
        /// <param name="columnName">the name of the column (from the Entity Model) that you are looking for</param>
        /// <returns>The DynamicData Control for the column that you are looking for</returns>
        public static Control FindFieldTemplate(this Control control, string columnName)
        {
            // code copied from internal method: System.Web.DynamicData.DynamicControl.GetControlIDFromColumnName
            // Since it is internal, it could change, but I needed to get to it
            return control.FindControl("__" + columnName);
        }

        public static FieldTemplateUserControl FindFieldTemplateUserControl(this Control control, string columnName)
        {
            var userControl = ((FieldTemplateUserControl)(control.FindFieldTemplate(columnName)));
            if (userControl == null) throw new Exception("Could not find FieldTemplate in Control for " + columnName);
            return userControl;
        }

        public static Control FindControlForColumn(this Control control1, string columnName)
        {
            var control = FindFieldTemplateUserControl(control1, columnName).DataControl;
            if (control == null) throw new Exception("Could not find control in Control for " + columnName);
            return control;
        }

        public static T FindControlForColumn<T>(this Control control, string columnName) where T : Control
        {
            return FindControlForColumn(control, columnName) as T;
        }

        public static object GetValueForColumn(this Control control, string columnName)
        {
            var actualControl = FindFieldTemplateUserControl(control, columnName).DataControl;
            return GetValue(control, actualControl);
        }

        public static T GetValue<T>(this Control control, string columnName)
        {
            object rawVal = GetValueForColumn(control, columnName);
            //return (T)Convert.ChangeType(rawVal, typeof(T));

            // this is a little better because it handles nullable types also
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(rawVal);
        }

        public static T GetValue<T>(this Control control1, Control control)
        {
            object rawVal = GetValue(control1, control);
            //return (T)Convert.ChangeType(rawVal, typeof(T));

            // this is a little better because it handles nullable types also
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(rawVal);
        }

        public static object GetValue(this Control control, Control actualControl)
        {
            if (actualControl is ITextControl)
            {
                return (actualControl as ITextControl).Text;
            }
            else if (actualControl is ICheckBoxControl)
            {
                return (actualControl as ICheckBoxControl).Checked;
            }
            else if (actualControl is ListControl)
            {
                return (actualControl as ListControl).SelectedValue;
            }
            else if (actualControl is HiddenField)
            {
                return (actualControl as HiddenField).Value;
            }
            else throw new Exception("Could not get value of unknown control type: " + actualControl.GetType().ToString());

        }

        public static void SetValue(this Control control, string columnName, object value)
        {
            Control actualControl = FindControlForColumn(control, columnName);
            SetValue(control, actualControl, value);
        }

        public static void SetValue(this Control control, Control actualControl, object value)
        {

            if (actualControl is ITextControl)
            {
                (actualControl as ITextControl).Text = Convert.ToString(value);
            }
            else if (actualControl is ICheckBoxControl)
            {
                (actualControl as ICheckBoxControl).Checked = Convert.ToBoolean(value);
            }
            else if (actualControl is ListControl)
            {
                (actualControl as ListControl).SelectedValue = Convert.ToString(value);
            }
            else if (actualControl is HiddenField)
            {
                (actualControl as HiddenField).Value = Convert.ToString(value);
            }
            else throw new Exception("Could not set value of unknown control type: " + actualControl.GetType().ToString());
        }
    }
}

Friday, October 15, 2010

Lessons in Dynamic Data, Domain Service, and DomainDataSource with ASP.NET 4

I have been working with Silverlight a lot lately and have come to love the Domain Service. I recently started a new ASP.NET based project and saw that in VS 2010 I can now create an ASP.NET Dynamic Data Domain Service Web Application. So, I tried it.

I have learned some things since I did this. Below is what I have learned.

Getting Started, Docs, etc.

  • For a good starting point to learn about Dynamic Data, click here.
  • Here are the best docs I can find for looking at lot of scenarios and customizations you may want to do with Dynamic Data. I recommend reading this.
  • There is sample code that is referenced in the docs above. I think the code may be a bit out of date though. Anybody know where newer sample code is?
  • Here is the Dynamic Data forum if all else fails.
  • Once you create a new project in Visual Studio 2010 the project does run. You need to do a few things first like create your model and Domain Service. This walks you through what you need to do.

Gotchas

  • If you create a custom page, you MUST have all the REQUIRED fields on the FormView in Edit mode, otherwise, the form will give your an error when you click the Update button. Click here for more details on this issue. Workarounds include setting Visible to false or creating a new FieldTemplate  or modify the existing implementation. Click here for details on how this can be done.

  • I tried to create a total independent page that uses the DynamicDataSource, a form view, and my Domain Service Class and it will not work. It can’t figure out the MetaData it needs to work. The solution is to create a directory under DynamicData\CustomPages. The name should match the name of the Entity (not Entity Set). Hint, the name is the singular, not plural if version usually. To create a custom Edit page for your entity, copy DynamicData\PageTemplates\Edit.aspx (and the .aspx.cs file) to the directory you created above. Correct the class names, etc and you should be in good shape. For more details, try here.
  • If you create a custom page in the DynamicData\CustomPages\<YourEntity>\Edit.ascx for example don’t use FormView1.FindControl() in the Page_Load() event. If you do it will cause the DropDownLists to not have an item selected in them. I am guessing it is just early for stuff that DynamicData is doing since if you look in the FieldTemplates a lot of stuff such as binding, etc takes place in the PageLoad event. My solution was to use the PreRender event to put my stuff there. That seems to work fine. No issues yet. :)

Here are some differences between the ASP.NET and Silverlight experience.

  • The Domain Service is actually a Domain Service CLASS in ASP.NET and doesn’t use WCF or anything like that from what I can tell. In Silverlight it is actually a Domain SERVICE and actually uses WCF under the hood to communicate with your Silverlight application.
  • I don’t seem to have to use .Include(“…”) queries in the Domain Service and [Include()] in the MetaData to make the ADO.NET Entity Framework pull in my related entities.

Thursday, October 14, 2010

Adding a border around text to make it look like a TextBox

The scenario applies to simple Label or Literals in ASP.NET. I am currently using a DynamicControl with the Mode set to ReadOnly. This causes the generation of a Literal and thus looks like plain text in the browser. This is great in most cases.

However, sometimes I want the text to have a border around it and maybe a different background to make it look like a read only TextBox.

Thankfully there is an easy solution. Using CSS we can define a style

.DDTextWithBorder
{
        border: solid 1px #bcbcbc;   
}

We could include background color if we wanted to change that also.

To use the style, we can put a span tag around whatever we want the border around and setting the class=”DDTextWithBorder” attribute.

An example of that is:

<span class="DDTextWithBorder"><asp:DynamicControl ID="TotalPointsDynamicControl" runat="server" DataField="TotalPoints" Mode="ReadOnly"/></span>

Another way is to just set the CssClass property of the control we want to put a border around.

<asp:DynamicControl ID="TotalPointsDynamicControl" runat="server" DataField="TotalPoints" Mode="ReadOnly" CssClass="DDTextWithBorder"/>

That’s it. Quite simple, but powerful.

DomainDataSourceView.PerformCudOperation error on updating a FormView.

If you have a REQUIRED field in your ADO.NET Entity Model, you MUST have it on your Form when you use the DomainDataSource, FormView, and Domain Service Class and it must be EDIT mode if you are using the DynamicDataControl. If you leave it off the form or set the mode to ReadOnly you will get a totally useless error like this.

[EntityOperationException: An error has occurred.] Microsoft.Web.UI.WebControls.DomainDataSourceView.PerformCudOperation(ChangeSetEntry operation, Action`1 operationPerformingEvent, Action`1 operationPerformedEvent) +331 Microsoft.Web.UI.WebControls.DomainDataSourceView.UpdateObject(Object oldEntity, Object newEntity) +195 System.Web.UI.WebControls.QueryableDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +115 Microsoft.Web.UI.WebControls.DomainDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +40 System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, IDictionary oldValues, DataSourceViewOperationCallback callback) +95 System.Web.UI.WebControls.FormView.HandleUpdate(String commandArg, Boolean causesValidation) +1154 System.Web.UI.WebControls.FormView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +408 System.Web.UI.WebControls.FormView.OnBubbleEvent(Object source, EventArgs e) +95 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37 System.Web.UI.WebControls.FormViewRow.OnBubbleEvent(Object source, EventArgs e) +112 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37 System.Web.UI.WebControls.Button.OnCommand(CommandEventArgs e) +125 System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +167 System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13 System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563

If you are lucky the field you set to ReadOnly will be a DataTime field or something and it will tell you that the date is not valid. If it is just a string field then you may get the useless error as shown above.

This probably won’t show up unless you try to create a Custom Page for one of your entities. The nice thing is that when you create a Custom Page you get full control over the layout of your entity. The problem is that you can create all kinds of frustrating issues like this one.

BTW, this is only an issue for datatypes that use the Text.ascx and DateTime.ascx controls. The reason is because these controls are implemented using a literal control instead of a Label, etc which has viewstate. Any datatype that has a _Edit.ascx counterpart won’t be affected and also any that have something that has viewstate as the underlying readonly implementation.

Work Arounds

Work Around – If you don’t want the user to see a field

You can always add the control to the FormView even if you don’t want the user to see it. The set the visible to false. This will allow it to work properly. All form validators will not be created which is good in for the most part.

If you are just doing an edit template then the above will work fine. However, if you are doing an insert template, then you will get errors about not being able to set the value because the value is illegal or invalid. An example of this is a DateTime can’t be set to null or an int can’t be set to null. If the field is required then non-nullable types will be used. This means you need to specify a default value.

The trick to specifying the default value is that you can’t do it in your entity’s constructor because since the FormView has the required field on the EditTemplate a value (null) will be set on your Entity after it is created (after the valid value you may have tried to default in the entities constructor. That is what is causing the error.

One solution is to use the ItemInserting event of the FormView. Here you will find a parameter that is of type FormViewInsertEventArgs. It has a collection of all the values that are being submitted.

For each of the items you added to the FormView and hide, you will need to set the default value they should have using the Values collection. The key is the name of Entity Property you bound to in the FormView. The exception to that is if you re binding to a Navigation property such as with a DropDownList. In this case the foreign key is actually what you will find in the Values collection, not the Navigation property name. The value is foreign key, not the related entity.

If you don’t want to think that hard, you can always just set the values of the DynamicControls you want to default using what ever method gets called when you click your insert button. In my case, I am going with the same LinkButtons that are used in the default insert template for Dynamic Data. This means that FormView1_ItemCommand is a good place to set the values of your DynamicControls. This is a bit easier because you don’t have to worry about DropDownLists in the same way. However, since you are dealing with different controls that is more thought also, so it is really up to you on which approach you want to take. The bottom line is that the value has to be there when the FormView passes it on to the DomainDataSource.

FYI, I have made working with DynamicControls must easier. It makes setting and getting values on forms that have DynamicControls on them trivial. Here is an example of what I am talking about.

FormView1.SetValue("DateCreatedUtc", DateTime.UtcNow);

Here is the link to the source code. I implemented it as an extension of the Control class.

Work Around – If you want it on the Edit mode of the FormView, but show as readonly.

Option 1

If you need the field on the FormView, but want it to be readonly when the FormView is in Edit mode, there is another solution.

Copy DyanmicData\FieldTemplates\Text_Edit.ascx (and the .ascx.cs file) to DyanmicData\FieldTemplates\TextAppearReadOnly_Edit.ascx (and .ascx.cs file). What comes before the underscore is not important, but what the name must end is _Edit.ascx and _Edit.ascx.cs.

Remove the validator controls as they are not needed. Add a literal control and bind it to the same value as the TextBox. Once you have done that, your .ascx file will look something like this:

<asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueEditString %>" />
<asp:TextBox ID="TextBox1" runat="server" Text='<%# FieldValueEditString %>' ReadOnly="true" Visible="false" />

Now open the .ascx.cs file. Remove all items that aren’t needed or don’t compile. You class will look something like this:

public partial class TextAppearReadOnly_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        TextBox1.ToolTip = Column.Description;
    }

    protected override void ExtractValues(IOrderedDictionary dictionary)
    {
        dictionary[Column.Name] = ConvertEditedValue(TextBox1.Text);
    }

    public override Control DataControl
    {
        get
        {
            return TextBox1;
        }
    }

}

Now, where ever you want a read only field on do something like this:

<asp:DynamicControl ID="DateCreatedDynamicControl" runat="server" DataField="DateCreated" Mode="Edit" UIHint="TextAppearReadOnly" />

The part to pay attention to is that the Mode is set to Edit and the UIHint specifies to use our control we created.

Option 2

I actually prefer this method as the semantics of option 1 don’t seem quite right. In this option, we will actually modify the default controls to implement what I call a bug fix. :)

  1. Open DynamicData\FieldTemplates\DateTime.ascx
  2. Change the line:

    <asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueString %>" />

    to

    <asp:Label runat="server" ID="Label1" Text="<%# FieldValueString %>" />

    Notice the only change I made is changing the type from Literal to Label and updated the ID to reflect the change also.
  3. Open DynamicData\FieldTemplates\DateTime.ascx.cs
  4. Add the following method:
    protected override void ExtractValues(IOrderedDictionary dictionary) {
                dictionary[Column.Name] = ConvertEditedValue(Label1.Text);
    }

  5. Add the DataControl property (or modify it if it already exists) as shown below

    public override Control DataControl { get { return Label1; } }

Do the Same for Text.ascx (and Text.ascx.cs).

Using this fix, you don’t have to change any of the properties on the DyanmicControl and the semantics are right. Here is an example of what you may have.

<asp:DynamicControl ID="DateCreatedDynamicControl" runat="server" DataField="DateCreated" Mode="ReadOnly" />

Notice that the Mode is ReadOnly which makes sense to me. This means that you can use the DynamicControl exactly the same regardless of the datatype and regardless of whether it is a required field or not.

Thursday, October 7, 2010

Adding a linked server in MS SQL Server

A linked server allows you to connect and query against a database on another MS SQL Server instance even if it is on another machine. Once you have created a linked server you can use the tables in the linked server just like you would use a local table (in most cases).

Let’s assume you have to instances of MS SQL Server on two different machine. On the first instance (called it SQL1) you have a database called MyDB1. On the second instance (call it SQL2) you have a database called MyDB2. Now we want to run a query from MyDB1 on MyDB2.

In general here is what we need to do

  1. Create a linked server
  2. Specify the credentials that the link will use

Specifically here is what we need to do.

  1. Open SQL Management Studio and open a query window for MyDB1.
  2. Create the linked server. I prefer the SQL statement way of doing this as I think the UI in MS SQL Management Studio under Server Object | Linked Server is confusing to use since it is made to work for all kinds of server besides MS SQL server. 

    Customize (change the items in red and green) the SQL statement below to point to your stuff and then execute it in the query window. Please note that the item in red is what will show up under the Server Objects | Linked Servers in SQL Server Management Studio. The item in green is the name of the database you want to get access to on the remote server.

    EXEC master.dbo.sp_addlinkedserver
    @server = N'MyDB2LinkedServer',
    @srvproduct=N'SQLNCLI', @provider=N'SQLNCLI', @datasrc=N'SQL2',
    @catalog=N'MyDB2'
  3. I can never seem to get Windows credentials to work for linked servers, so I usually go with a named SQL Server user. The example below uses SQL Server user named DB2User and has a password of db2user. Please use a better password in a real environment.

    Customize (change the items in red and green) and execute the sql statement in the same query window. Please note the item in red MUST match what you used in the first statement (above). The items in green must be the username and password of the user / login on the remote server you are trying to access and must have access to the database you are trying to access on that same remote server.

    EXEC sp_addlinkedsrvlogin 'MyDB2LinkedServer', 'false', NULL, 'DB2User', 'db2user'

 

Now that you have the link established, it should show up in SQL Server Management Studio under Server Objects | Linked Servers. If it doesn’t try right-clicking the Linked Servers node and choose Refresh.

Now that you have a link it is time to give it a try. We’ll do this by selecting from table on the remote server from the local server. Using the scenario discussed earlier, follow the steps below to test your linked server.

  1. In the same query window or a new one. For a new one, open SQL Management Studio and open a query window for MyDB1.
  2. Customize the statement below for your stuff and execute it.

    select count(1) from MyDB2LinkedServer.MyDB2.dbo.MyTable1

    Here we are selecting from a table called MyTable1 on the MyDB2 database on SQL2 all the while we are still connected to MyDB1 on SQL1. If you tables are not in the dbo schema you will need to change dbo to be the name of htat schema. Typically you can tell just by looking in SQL Server Management Studio and browsing the tabes. If there is just a table name, then it is almost certainly dbo. If it same xxx.MyTable1 then the schema is called xxx and the above statement will need to have have dbo replaced with xxx.

    Pretty cool. You can then join tables, update and update rows, etc just as you would any other tables in your local database.

Thursday, July 8, 2010

Unable to update the EntitySet 'MyEntity' because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.

If you are using the ADO.NET Entity Framework and a Domain Service (I don’t think you have to be using a Domain Service to have this issue) and you get the error:

Unable to update the EntitySet 'MyEntity' because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element to support the current operation.

One common reason you get this is that the table you are trying to update doesn’t have a single primary key in the database. This then causes the Entity Framework to create a compound key of all the non-nullable columns.

To solve the issue, just create a primary key on the table and update your model. You will have to manually change the Entity Key property to False for all the properties that are not your primary key.

If you are not so lucky to have just forgot to create a primary on the database table, then you may check out this forum for more info on options. I was lucky, I just needed to add a primary key to my table. :) Good luck.

Tuesday, July 6, 2010

WinDirStat – What is eating up all my hard disk free space?

Have you ever wondered where all your free space on your hard drive has gone? Have you every wondered how to find files or folders that are taking up a lot of space? Or maybe what percent of your disk is taken up by the Windows directory?

Well if you have, I suggest using WinDirStat. It is OpenSource and thus free. It takes just a minute to download and install and takes around 1MB of diskspace. It is quite fast at analyzing your disk also. I highly recommend it.

Here is the link for info (including screenshots) and download links.

Friday, June 11, 2010

ComboBox Solutions for Silverlight 3 and Silverlight 4

Silverlight 3 ComboBox Solutions

Proper Way to bind ComboBoxes to Associated Entities / Foreign Keys? Look about half way down for a post by ScottNZ on 8/13/2010 for the good idea.

Silverlight 3 ComboBox Control This solution works well I think and is even compatible with Silverlight 4. The one enhancement I would make to it for SL4 is use the SelectedValue and SelectedValuePath instead of SelectedObject. If you use SelectedValue and SelectedValuePath then the DataForm (DataField really) knows how to make it appear with a red box around it if you mark the foreign key property (if you are using RIA) as Required and there is nothing selected. Very nice. The error message is lame, but still better than nothing.

Silverlight ComboBox control and data binding by Rockford Lhotka Basically gives source code on how to make the SL3 ComboBox work much like the SL4 ComboBox. I have not tried it, but he is good so I’m sure it works, and it is a good example of how to extend a Silverlight control.

Just Geeks: A better way of using the ComboBox on a DataForm in Silverlight 3 – I wrote this one. Not too much different that most solutions above or at least some combination of them. I do go into what to do for POCO entities.

Just Geeks: Using a ComboBox on a DataForm for Silverlight 3 – I wrote this one also. It was my first attempt at using a ComboBoxes. The biggest take away from it is that you can populate the ComboBox in the ContentLoaded event of the DataForm.

Silverlight 4 ComboBox Solutions

NOTE: These won’t work in Silverlight 3 because SL4 added the SelectedValue and SelectedValuePath properties that work with the EF ForeignKey support.

Binding to Silverlight ComboBox and Using SelectedValue, SelectedValuePath, and DisplayMemberPath This one is actually good but assumes you know how to populate your ComboBoxes. I recommend using resources.

Silverlight 4 Rought Notes: SelectedValue It does a pretty good job of showing how to use the new SelectedValue, SelectedValuePath, etc. It uses locally defined data in example so it you’ll have to make the leap on how this is done in real code.

Tuesday, May 25, 2010

How to add a default value to column in T-SQL (SQL Server)

If you have a Not Null column in SQL Server and you want have a default value you can add that at any time. The most difficult situation I have seen is doing it when you want the default to be the current date.

In the example below I have a table called Person and a column CreatedDateTimeUtc that I want to default to the current utc date if the value is null. This will occur on both update and insert.

ALTER TABLE [dbo].[Person] ADD  DEFAULT (GetUtcDate()) FOR [CreatedDateTimeUtc]

Monday, May 17, 2010

Unit Testing Asynchronous calls in Visual Studio 2010

I am simply amazed how much effort I had to go through to figure out how to test asynchronous calls in Visual Studio 2010 (VS2010). In the end, I was able to figure it out with the help of some blogs that I read.

VS2010 ships with integrated Unit Testing which I would like to take advantage of. I am writing a Silverlight application that calls a Windows Workflow Foundation service that I implemented using the WCF Workflow Service Application. I really like it, but I want to be able to unit test the workflow service.

The only way I found to test a WCF Workflow Service Application that I could find was to add a Service Reference to my Unit Test project. This is good for me because that is how Silverlight will call it. The problem is that the WCF Workflow Service Application can’t be called synchronously. So, we have to call it Asynchronously. The problem is that the Unit Test framework used in VS2010 does not support Asynchronous calls in  a Unit Test. Well, it runs, but doesn’t wait for the response to the Async call, so the test is pretty worthless.

Now that you know what I am trying to do, here is what I found as solutions.

Option 1: Simulate Synchronous call using an Asynchronous call

Here is a class I created to simplify the process of make an asynchronous call appear to be synchronous.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MyApp.Tests
{
public class AsyncTest
{

// max number of milliseconds to wait for an asynchronous call
int timeout = -1;

public AsyncTest()
{
// if debugging, make it a much larger like infinity
if (System.Diagnostics.Debugger.IsAttached)
{
timeout = -1; // infinity (wait for ever)
}
else
{
timeout = 20 * 1000; // 10 seconds
}
}

public AsyncTest(int timeout)
{
this.timeout = timeout;
}

// we'll use this to make the current thread wait until our asynchrous call finishes
ManualResetEvent block = new ManualResetEvent(false);

// we'll use this to flag if/when our async call finishes
bool isAsyncDone = false;

public void Done()
{
isAsyncDone = true; // flag that we are done (do NOT do this after calling block.Set() this will cause race conditions!!!!)
block.Set(); // tell the calling / this thread that it can continue now.
}

public void Wait()
{
block.WaitOne(timeout, false); // wait until block.Set() is called or the timeout expires (which ever comes).
Assert.IsTrue(isAsyncDone, "Test took too long"); // if it took too long then report it to the test framework.
block.Reset(); // set the event to non-signaled before making the next asynchronous call.
}
}
}

Here is an example of how you would use it to create a method that acts like a synchronous method, but calls an asynchronous WCF Service.

public GetWorkflowStatusCompletedEventArgs GetWorkflowStatus(long requestID)
{
AsyncTest at = new AsyncTest();

GetWorkflowStatusCompletedEventArgs returnedArgs = null;

// setup our service reference and callback for when it is done
ServiceClient wf = new ServiceClient();
wf.GetWorkflowStatusCompleted += delegate(object sender, GetWorkflowStatusCompletedEventArgs e)
{
returnedArgs = e;
at.Done();
};


wf.GetWorkflowStatusAsync(requestID);
at.Wait();

return returnedArgs;
}

I created one of these methods for each of the asynchronous methods I wanted to test. In fact I created a helper class to hold them. Now, in my class that has all my tests in it, I just call the methods on this helper class which are synchronous. Now the test run properly.

For completeness, here is what the unit test (testmethod) would look like.

[TestMethod]
public void TestCanGetWorkflowStatusTwiceInARow()
{
var status = Helper.GetWorkflowStatus(1234);
Assert.AreEqual<long>(status.RequestID, requestData.RequestID, "The wrong request id was returned.");
Assert.IsTrue(status.RequestID > 0);
}
Now I can write a unit test just as easily as I do any other unit test. The synchronous / asynchronous issue is encapsulated in a helper class. I like it. Not much extra work either. Especially since each helper method I write is almost identical. It could be generated if desired (using CodeSmith, etc).
I wish I could take credit for all this, but I can’t. The solution / implementation is completely mine, but the underlying technique is borrowed. For more info on those links, see here:

Option 2: Use the Silverlight Unit Test Application

I think this method is a reasonable approach, but for testing a WCF Service, it seems a bit unnatural to me. I like Option 1 better because I want my test results to be managed in VS2010. If nothing else other than no browser opens and also that you can block check-in of code if tests fail. The integrated Unit testing just seems a bit more integrated with VS2010.
I do think the Silverlight Unit Test Application is a great testing technology. However, I think it is best and most natural for testing Silverlight applications, not the web services they call.
There are lots of good blogs on the subject, so I won’t repeat it here. Here are some of the blogs that I found particularly useful when I went down this road.

Tuesday, May 4, 2010

Getting Current User when using WCF and Silverlight

First off, when you start to create a WCF Service in Visual Studio 2010 or 2008 for that matter, you can choose WCF Service, but if you are using Silverlight as the client, you do NOT want to select this. You want to select, Silverlight-enabled WCF Service. If you don’t or didn’t you can follow the instructions here to make sure a few things are in place and then you will be in the same position as if you had selected the Silverlight-enabled WCF Service.

All I want to do is get the username of the user that is using my Silverlight application. Note, this also opens the door to ASP.NET roles.

Alot of what I read said that if I mess with my app.config and turn on transport or message security then I can get the user if I go to System.ServiceModel.ServiceSecurityContext.Current. Well, maybe that was for a Self-Hosted WCF service or some other scenario, but I could not get it to work in my tests with Silverlight with IIS hosted WCF Service. I think my biggest difficulty with these docs were that all the configuration tags that I expected to see in the web.config (they had an app.config) were not there, but yet I had a working (without security) WCF Service.

I had to assume it uses some defaults. I figured out that I was right. If you read A Developer's Introduction to Windows Communication Foundation 4 you will understand much better. It is a fairly lengthy read, but well worth it. There is actually a section on Workflow Foundation 4, but the first part of the article is most excellent in describing the defaults and how they work. For instance search it for ProtocolMapping to see that the defaults include basicHttpBinding, netTcpBinding, netNamedPipeBinding, and netMsmqBinding. They are defined in the Machine.config. WCF 4 also support inheritance / merging of configuration items. Very cool.

I am using an IIS hosted WCF service. I want to use Windows Authentication for authentication. Nothing fancy. What I found works well and quite easily is ensure the following things are in specified and in synch with each other. They must all agree!

Web Server
  • IIS has anonymous access disabled (not enabled).
  • IIS has Integrated Windows authentication enabled.
  • If you are using Visual Studio 2010 and using the built-in dev server, the default settings are fine. I did NOT have to check the NTLM Authentication checkbox.
Web.config
  • This is needed to have ASP.NET be able to get security info as well.
<system.web>
<authentication mode="Windows"/>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
  • Make sure you have aspnet compatability enabled as follows:
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"  aspNetCompatibilityEnabled="true"/>
Your Service Class
  • Make sure to add the following above your class for your WCF Service. You can also use Required, instead of of Allowed
    [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]

And now the moment of glory. You can now get the user just like you would in ASP.NET.

System.Web.HttpContext.Current.User.Identity.Name

References: A Developer's Introduction to Windows Communication Foundation 4

Tuesday, April 27, 2010

Creating a LogError Activity

Surprisingly, in Visual Studio 2010 there is not an Activity in Windows Workflow Foundation (WF) 4.0 that writes an error to the Windows Event Log / Viewer. The good news is that it is very easy to write. Below are the instructions for creating one.

Step 1: Add new Code Activity

Add a new Code Activity called LogError to your Workflow project (This could be any of them, but I recommend putting your Activities in an Activity Library project.).

Step 2: Modify Code Activity to look similar to the following example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Diagnostics;

namespace MyApp.MyActivities
{

public sealed class LogError : CodeActivity
{
// Define an activity input argument of type string
public InArgument<string> PreMessageText { get; set; }
public InArgument<Exception> Exception { get; set; }

protected override void Execute(CodeActivityContext context)
{
Log(PreMessageText.Get(context), Exception.Get(context));
}

public void Log(string preMessageText, Exception ex)
{
string sourceName = "My App";
string logName = "Application"; // i.e. System, Application , or other custom name

if (!EventLog.SourceExists(sourceName))
{
EventLog.CreateEventSource(sourceName, logName);
}

string message = string.Empty;
message += ex.Message + "\r\n";
message += ex.StackTrace;

EventLog.WriteEntry(sourceName, preMessageText + "\r\n" + message, EventLogEntryType.Error);

}
}
}

To use the Activity just compile your project. It will then show up in your Toolbox. You will probably want to drag a TryCatch Activity onto your workflow. Then drag the LogError Activity we created to the Exception section of the TryCatch Activity. Set the Exception property to the argument name in the Exception section.

Misleading error message in Windows Workflow Foundation 4.0

If you are running a Windows Workflow Foundation 4.0 (in Visual Studio 2010) and you are testing it with the WCF Test Client and you get a message similar to the following:

Failed to invoke the service. Possible causes: The service is offline or inaccessible; the client-side configuration does not match the proxy; the existing proxy is invalid. Refer to the stack trace for more detail. You can try to recover by starting a new proxy, restoring to default configuration, or refreshing the service.

The operation could not be performed because WorkflowInstance 'cb123a26-34bd-4ab8-876f-63dee2080b42' has completed.

Server stack trace:

   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

   at IService.GetData(String inParameter1)

   at ServiceClient.GetData(String inParameter1)

The good news is that if you have not messed with bindings, etc, and you made a simple change to the workflow and your service started throwing this exception, it is likely the message is just misleading. I have concluded that you will get this message anytime an exception is thrown during the execution of the workflow. This could be something as simple as a null pointer or much more complex.

The question is how do we figure out what the real exception is. A more important question is how do we catch and log these exception. Without the logging, we won’t know if our users are having issues and how have a clue what the cause is.

One way to address this issue is to Use the TryCatch Activity in Windows Workflow Foundation (WF) Designer in Visual Studio 2010. This works just like a try-catch-finally would work in C#. You can create a custom Code Activity called something like LogError. Click here for details on creating this custom Activity. You can then use it in the catch portion of the TryCatch activity.

You can put the TryCatch Activity at the highest level in your workflow to server as a catch all or you can use it particular points in your workflow. Just like when coding, it is often appropriate to do both.

Now when you try to run test your Workflow you will see your error in the Windows Event Log / Viewer. Since the workflow didn’t return the expected response, you still get this generic / useless error, but at least you know the cause now.

If after all this, there is no exception being thrown then it is likely you are trying to send an message to your workflow that is not valid. By not valid, I mean it could be that the Message you are sending is not to the Current Message. Consider the case where you have 2 ReceiveRequest Activities and they are in a Sequence. If you try to send a Message to the second one before the first one this is not valid. Why? Because they are in a sequence. The first Activity must complete before the second one can be executed. That is the vary nature of a workflow. If you need them to be able to be called regardless of the sequence, then you should probably use the Parallel Activity.

Lastly, if you are executing the Activities in order and still getting the error, make sure you are referencing the same CorrelationHandle and that you have specified a key for it to use as the correlation object. This is essentially a primary key for an instance of the workflow. IN WF3 this was the workflow id. In WF4, you can use a key in your data or you can use a GUID like WF3 did, but in any case, you need to tell all your Receive Activities what you want to use to make the correlation. If you don’t have a correlation handle and key defined then WF4 will have now way of telling what instance of the workflow you are trying to access.

Wednesday, April 14, 2010

SharePoint stsadm.exe export / import issues

I am exporting a web from WSS 3.0 64-bit with https and importing to MOSS 2007 32-bit with just http on another server. I ran into some errors issues along the way. Here is what I ran into and how I got around it.

Keep in mind, the export/import commands work on the specified site AND ALL SUB-SITES, not just the one you specify.

Exporting the Site

I wanted to export the security, all versions, etc so that I have EVERYTHING that was on the SharePoint web (site). Here is the commend I used:

c:
cd "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\"
stsadm -o export -url https://yoursite/level1/level2/yourSiteHere -filename c:\yourSiteHere -includeusersecurity -haltonwarning -haltonfatalerror -versions 4 –nofilecompression

This will create a directory: c:\yourSiteHere. There are lots of files, etc so you may want to zip the directory if you are moving it to another server because copying one file is much faster than many small ones.

You can remove the –nofilecompression switch, but you may need to edit some of the files in the directory later, and I couldn’t get it to work with the import. I suspect because I had multiple files created when it exported.

Import the Site

Once you copy and unzip the directory to your new server (or same on if you want to).

Tip: When you unzip it be sure that the contents are just as they were on the other server, and not in a parent folder as Windows unzip typically does. Move the folders around to correct this or adjust the path below when you execute the command.

Best case is the following command will work and there is nothing more to do.

c:
cd "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\BIN\"
stsadm -o import -url http://yourNewServer/newLevel1/yourSiteHere -filename C:\yourSiteHere -includeusersecurity –haltonwarning -haltonfatalerror -updateversions 1 –nofilecompression

NOTE: I used updateversion 1 instead of updateversions 2. I couldn’t get updateversion 2 to work because it coudn’t delete one of the files. Using 1 instead will only add to the files, not delete and replace the files that are there. Since this site has never been on this server, I think updateversions 1 works well.

You an use any path on the new server you want. It doesn’t have to be the same as the one on the previous server.

Import Issues?

You may run into some issues importing.

You may get some of these errors (you’ll only see the others after you correct each error in succession).

The 'AllowAutomaticASPXPageIndexing' attribute is not declared.
The 'ASPXPageIndexMode' attribute is not declared.
The 'NoCrawl' attribute is not declared.
The 'CrawlAllSchema' attribute is not declared.

To correct the issues, just open up the C:\yourSiteHere directory and find the Manifest.xml file. Open the file in Notepad or your favorite text editor.

Delete the following attributes (search is easiest).

AllowAutomaticASPXPageIndexing="true" ASPXPageIndexMode="Automatic"
NoCrawl="false"
CacheAllSchema="false"

Save your changes to he Manifest.xml file and run the import command again. It will hopefully work now.