Friday, October 18, 2013

Extend WCF automatically generated DTO with partial classes

Suppose that you have some WCF service which has web method which returns instance of Foo class (this class should be marked with [DataContract] attribute and its members with [DataMember] attribute as you probably know) and VS generated proxy for this web service. VS also will generate all dependent classes necessary for successful compilation of the proxy, including mentioned Foo class. Now you need to extend it with partial class (there may be a lot of reasons), how to do it?

The answer depends on actual configuration of the service and client, but there is one thing which you should keep in mind. Let's assume that we have the following automatically generated Foo class on the client side:

   1: [Serializable]
   2: public class Foo
   3: {
   4:     [XmlElement]
   5:     public string Title { get; set; }
   6: }

We want to add additional property which will be used only on client side, so we create partial class for it like this:

   1: public partial class Foo
   2: {
   3:     public string Status { get; set; }
   4: }

With this approach we may get the following exception:

There was an error reflecting 'Foo'.
at System.Xml.Serialization.XmlReflectionImporter.ImportMembersMapping(XmlReflectionMember[] xmlReflectionMembers, String ns, Boolean hasWrapperElement, Boolean rpc, Boolean openModel, RecursionLimiter limiter)

In order to avoid it, add [XmlIgnore] attribute for your property:

   1: public partial class Foo
   2: {
   3:     [XmlIgnore]
   4:     public string Status { get; set; }
   5: }

You may also try to change auto property from example above to classic property with private field and add [NonSerializable] attribute to the field, but in this case added property won’t be serialized on the client side, which in turn may cause another problems.

Hope that this information will help someone.

Saturday, October 12, 2013

Problem with WebPartPageUserException in Sharepoint 2013 web parts

In Sharepoint 2013 web parts are created in different way comparing with previous versions. Now with .ascx and .ascx.cs files, which also were created before, there is new .ascx.g.cs file – automatically generated file which contains code for all elements added on .ascx file. I already wrote about one problem with new web parts here: Fix bug in Visual Studio 2012 with deleting generated ascx.g.cs files for web parts. In this post I will write about another problem, related with them. Your web part may work properly until you will add new element to ascx file. After that you may get the WebPartPageUserException:

The default namespace "http://schemas.microsoft.com/WebPart/v2" is a reserved namespace for base Web Part properties. Custom Web Part properties require a unique namespace (specified through an XmlElementAttribute on the property, or an XmlRootAttribute on the class).
   at Microsoft.SharePoint.WebPartPages.TypeCacheBuilder.CheckNamespace(String ns, PropertyInfo pi)
   at Microsoft.SharePoint.WebPartPages.TypeCacheBuilder.EnsureNamespace(PropertyInfo pi, XmlAttributes xmlAttrs)
   at Microsoft.SharePoint.WebPartPages.TypeCacheBuilder.CreateXmlSerializer(Storage storage, Boolean buildPersistedNames, Boolean shouldExcludeSpecialProperties, Hashtable& persistedNames, Hashtable& namespaces, Hashtable& dwpNamespaces)
   at Microsoft.SharePoint.WebPartPages.TypeCacheEntry.ThreadSafeCreateXmlSerializer(XmlSerializer& serializer, Storage storage, Boolean buildPersistedNames, Boolean shouldExcludeSpecialProperties)
   at Microsoft.SharePoint.WebPartPages.TypeCacheEntry.get_XmlSerializer()
   at Microsoft.SharePoint.WebPartPages.WebPart.ParseXml(XmlReader reader, Type type, String[] links, SPWeb spWeb)
   at Microsoft.SharePoint.WebPartPages.WebPart.AddParsedSubObject(Object obj)

I faced with this problem when added new <script> element with reference to javascript file on top of ascx. But it is not stable step to reproduce the problem. In the same project we had another web parts with added scripts already, which worked properly.

This problem comes from Microsoft.SharePoint.WebPartPages.WebPart, or more specifically from serializer used in this class. Because of some reason it “thinks” that we used reserved xml namespace "http://schemas.microsoft.com/WebPart/v2" for web part property in web part declaration in .webpart file, which is of course not true: in this case we don’t even have .webpart file with xml declaration. Instead we have ascx file and Sharepoint uses the same serializer, which it uses when deserialize web part from xml. The quick way to fix it is to change base class from Microsoft.SharePoint.WebPartPages.WebPart to System.Web.UI.WebControls.WebParts.WebPart. But if you want still use Microsoft.SharePoint.WebPartPages.WebPart because of some reason (in my practice I don’t remember the case when using of Microsoft.SharePoint.WebPartPages.WebPart gave advantage comparing with System.Web.UI.WebControls.WebParts.WebPart), you can use the following workaround.

First of all let’s see what code is added to .ascx.g.cs file when we add <script> tag into .ascx file:

   1: [global::System.ComponentModel.EditorBrowsableAttribute(global::System
   2: .ComponentModel.EditorBrowsableState.Never)]
   3: private void @__BuildControlTree(global::UPM.Internet.Raflatac.Web.UI.WebControls
   4: .WebParts.RibbonRecProduct.RibbonRecProduct @__ctrl) {
   5:     System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
   6:     @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl(
   7: "\r\n\r\n<div>\r\n    <script type=\"text/javascript\" src=\"/_layouts/15/test/js/test.js?r" +
   8:                 "el=1\"></script>\r\n</div>\r\n\r\n"));
   9:     global::System.Web.UI.HtmlControls.HtmlGenericControl @__ctrl1;
  10:     @__ctrl1 = this.@__BuildControldivSearch();
  11:     @__parser.AddParsedSubObject(@__ctrl1);
  12:     @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n\r\n"));
  13:     global::System.Web.UI.HtmlControls.HtmlGenericControl @__ctrl2;
  14:     @__ctrl2 = this.@__BuildControldivResults();
  15:     @__parser.AddParsedSubObject(@__ctrl2);
  16:     @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("\r\n\r\n"));
  17:     global::System.Web.UI.HtmlControls.HtmlGenericControl @__ctrl3;
  18:     @__ctrl3 = this.@__BuildControldivNoResults();
  19:     @__parser.AddParsedSubObject(@__ctrl3);
  20: }

As you can see script is added as LiteralControl on line 6. Let’s see now code of Microsoft.SharePoint.WebPartPages.WebPart.AddParsedSubObject() method, which is first method from stack trace from WebPart class:

   1: protected override void AddParsedSubObject(object obj)
   2: {
   3:     LiteralControl control = obj as LiteralControl;
   4:     if ((control != null) && !this._hasParsedLiteralControlDWP)
   5:     {
   6:         string text = control.Text;
   7:         if (text.Trim().Length > 0)
   8:         {
   9:             SPWeb web;
  10:             try
  11:             {
  12:                 web = Utility.CurrentWeb();
  13:             }
  14:             catch (InvalidOperationException)
  15:             {
  16:                 throw;
  17:             }
  18:             catch (Exception)
  19:             {
  20:                 throw new WebPartPageUserException(
  21: WebPartPageResource.GetString("InvalidWebPartChild"));
  22:             }
  23:             try
  24:             {
  25:                 Type type = base.GetType();
  26:                 EmbeddedXmlReader reader = new EmbeddedXmlReader(
  27: new StringReader(text), type, web);
  28:                 WebPart webPartFrom = ParseXml(reader, type, null, web);
  29:                 if (webPartFrom.UnknownXmlElements.Count > 0)
  30:                 {
  31:                     foreach (XmlElement element in webPartFrom.UnknownXmlElements)
  32:                     {
  33:                         if ((element.NamespaceURI == "http://schemas.microsoft.com/WebPart/v2")
  34: && ((string.Compare(element.Name, "Assembly",  true, CultureInfo.InvariantCulture) == 0)
  35: || (string.Compare(element.Name, "TypeName", true, CultureInfo.InvariantCulture) == 0)))
  36:                         {
  37:                             throw new WebPartPageUserException(
  38: WebPartPageResource.GetString("InvalidWebPartTag"));
  39:                         }
  40:                     }
  41:                 }
  42:                 this.InheritProperties(webPartFrom, reader.PropertyNames);
  43:                 this._hasParsedLiteralControlDWP = true;
  44:                 return;
  45:             }
  46:             catch (WebPartPageUserException)
  47:             {
  48:                 if ((SPContext.Current != null) && !SPContext.Current.IsDesignTime)
  49:                 {
  50:                     throw;
  51:                 }
  52:             }
  53:             catch (Exception)
  54:             {
  55:                 throw new WebPartPageUserException(
  56: WebPartPageResource.GetString("InvalidWebPartChild"));
  57:             }
  58:         }
  59:     }
  60:     base.AddParsedSubObject(obj);
  61: }

In the beginning of the method (see lines 3-4) it check whether the added control is LiteralControl and if yes, executes block of code, which looks like on the code of deserializing of web part from xml (WebPart webPartFrom = ParseXml(reader, type, null, web)) and then initialize properties of current web part from properties of deserialized web part (this.InheritProperties(webPartFrom, reader.PropertyNames)).

It sounds a little bit crazy, but above code looks like on the one more way of how we can initialize web part properties for web parts in Sharepoint. I.e. add xml declaration of web part (from .webpart file) directly to ascx file with properties initialization, and these values will be used for your web part. I tried to do it, but got the same WebPartPageUserException. Another (most likely) reason is that there is a bug in visual web parts in Sharepoint 2013. See below for more details.

At the moment based on the findings above we can apply the following workaround: enclose <script> element with <div runat=”server”></div> (runat=”server” is important, see below why). After this generated code will be changed:

   1: [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel
   2: .EditorBrowsableState.Never)]
   3: private global::System.Web.UI.HtmlControls.HtmlGenericControl @__BuildControl__control2() {
   4:     global::System.Web.UI.HtmlControls.HtmlGenericControl @__ctrl;
   5:     @__ctrl = new global::System.Web.UI.HtmlControls.HtmlGenericControl("div");
   6:     System.Web.UI.IParserAccessor @__parser = ((System.Web.UI.IParserAccessor)(@__ctrl));
   7:     @__parser.AddParsedSubObject(new System.Web.UI.LiteralControl(
   8: "\r\n    <script type=\"text/javascript\" src= uts/15/test/js/test.js?rel=1\"></s" +
   9:                 "cript>\r\n"));
  10:     return @__ctrl;
  11: }

I.e. now it will use HtmlGenericControl instead of LiteralControl. If you would enclose it with <div></div> without runat=”server” it will still use LiteralControl and you will get the same error.

In order to complete the picture, let’s see what code is generated for another web part in the same project with <script> element, which works:

   1: private void @__Render__control1(System.Web.UI.HtmlTextWriter @__w,
   2: System.Web.UI.Control parameterContainer) {
   3:     @__w.Write(@"
   4:  
   5: <script type=""text/javascript"" src=""/_layouts/15/test/js/test.js""></script>
   6:  
   7: <div class=""..."">
   8: <p>");
   9: ...
  10: }

I.e. it uses completely different approach because of some reason: instead of adding text via LiteralControl or HtmlGenericControl, it writes it via HtmlTextWriter.

Let’s summarize open questions:

1. Why for one web part generated code adds text via HtmlTextWriter and it works, but for other via LiteralControl, which fails. Both web parts are in the same project, inherit the same Microsoft.SharePoint.WebPartPages.WebPart class and <script> element was added as first element in ascx file for both of them.

2. For what reason MS added ability to initialize web part properties from xml, added to ascx file. My first thought was that it was added for simplifying initialization of the properties for cloud environments (when you can’t provision .webpart file to the file system), but then I checked that this code exists in Sharepoint 2007 and 2010 (in Sharepoint 2007 it is a bit different, but uses the same idea). In order to say something we should get working example.

There may be some reasons for this behavior of course, but it also can be that this is just a bug in visual web parts code generation and it uses AddParsedSubObject() method where it should not use it (like in second example where it uses HtmlTextWriter). If you will have further information about this problem, please share it in comments.

Friday, October 11, 2013

Fix problem with flooded event viewer with 326 and 327 messages from ESENT source

On Windows you may face with the problem that your event viewer is flooded with 326 and 327 messages from ESENT source. New events appear each several seconds, so it is not possible to use event viewer for troubleshooting. Here are messages for these events:

326:

svchost (6224) The database engine attached a database (2, C:\Windows\system32\LogFiles\Sum\SystemIdentity.mdb). (Time=0 seconds)
Internal Timing Sequence: [1] 0.000, [2] 0.000, [3] 0.000, [4] 0.000, [5] 0.000, [6] 0.000, [7] 0.000, [8] 0.000, [9] 0.000, [10] 0.000, [11] 0.000, [12] 0.000.
Saved Cache: 1

2

327:

svchost (6224) The database engine detached a database (2, C:\Windows\system32\LogFiles\Sum\SystemIdentity.mdb). (Time=0 seconds)
Internal Timing Sequence: [1] 0.000, [2] 0.000, [3] 0.000, [4] 0.000, [5] 0.000, [6] 0.000, [7] 0.000, [8] 0.000, [9] 0.000, [10] 0.000, [11] 0.000, [12] 0.000.
Revived Cache: 0

3

Solution is to stop User Access Logging Service from Windows services:

1

After that evens should stop flooding the event log.

Friday, October 4, 2013

Problem with trimmed html content in search index in Sharepoint 2013

If you use rich html fields (fields with Type = “HTML”) in your content type for publishing pages, then you may face with the problem that after crawling, content of these fields is trimmed, i.e. is shown as plain text. For example, imagine that you have authoring web application and create publishing pages there with custom rich html fields. Then by using cross site publishing these pages should be shown on consumer web application. On the page which is used for displaying authoring content on consumer web application there are several Catalog Item Reuse web parts, and one of them shows content of custom rich html field, which may show html content as plain text.

As you probably know, Catalog Item Reuse web part retrieves content from search index. So there may be several reasons for the problem:

  • Content of rich html fields is trimmed during crawling;
  • Item reuse web part trims html content.

Let’s start with first one and assume that we have the following field declaration:

   1: <Field ID="..."
   2:     SourceID="http://schemas.microsoft.com/sharepoint/v3"
   3:     DisplayName="MyField"
   4:     Group="Custom fields"
   5:     Type="HTML"
   6:     RichText="TRUE"
   7:     RichTextMode="FullHtml"
   8:     Required="FALSE"
   9:     Sealed="TRUE"
  10:     StaticName="MyField"
  11:     Name="MyField" />

First of all try to set RichHtml=”FALSE” in field declaration. Side effect is that field content will be shown encoded in authoring site by OTB field controls, but html won't be trimmed in search index. There is quite simple workaround: you may create custom control for displaying field content on authoring site or decode html in standard control by javascript.

If it won't help ensure that SourceID attribute is added to field declaration like shown above. Without it search won’t work properly. In one of my previous posts I wrote about similar problem with managed metadata (see Problem with not crawled managed metadata fields in Sharepoint 2013). For rich html fields when SourceID attribute is specified Sharepoint creates 2 crawled properties for your field: ows_MyField and ows_r_HTML_MyField. For second one it creates also managed property, however you should create managed property, map it to the first one and use it in your queries (second may not work as experience showed).

In order to make Item reuse web part rendering html content properly you need to specify RenderFormat property for Catalog reuse web part:

   1: <property name="RenderFormat" type="string">&lt;Format Type=&quot;HTML&quot; /&gt;</property>

If you will put not encoded xml there you will get error:

Exception calling "ImportWebPart" with "2" argument(s):
"The file you imported is not valid. Verify that the file is a Web Part description file (*.webpart or *.dwp) and that it contains well-formed XML."

It was interesting to find why RenderFormat should be specified in the above form. It was not documented anywhere, so I checked the code of CatalogItemReuseWebPart.GetValueToRender method:

   1: private string GetValueToRender()
   2: {
   3:     ...
   4:     if (string.IsNullOrEmpty(this.RenderFormat))
   5:     {
   6:         return CatalogItemUtilities.GetRenderValueUsingPropertyType(propertyName,
   7:             propertyValueFromResult);
   8:     }
   9:     return CatalogItemUtilities.FormatDataForRendering(propertyValueFromResult,
  10:         SPHttpUtility.HtmlDecode(this.RenderFormat));
  11: }

As you can see, if RenderFormat property is not empty, it tries to decode it first and then pass to CatalogItemUtilities.FormatDataForRendering() method. Then in FormatDataForRendering it does the following:

   1:  
   2: internal static string FormatDataForRendering(string data, string renderFormat)
   3: {
   4:     ...
   5:     XDocument document = XDocument.Parse(renderFormat,
   6:         LoadOptions.PreserveWhitespace);
   7:     XAttribute attribute = document.Root.Attribute("Type");
   8:     ...
   9: }

I.e. it loads RenderFormat property to XDocument and tries to get Type attribute of the root element. So property should be encoded and it should be correct xml. It was enough in order to guess the correct format for the property. Code is the best documentation :).

Wednesday, October 2, 2013

Speaking on Finland Sharepoint User Group

Today I was speaking on Finland Sharepoint user group meeting in Helsinki about problems and solutions of upgrading internet and extranet sites from SP2010 to SP2013. It was nice meeting and nice attendees with living interest to the subject. Hope that it was interesting to all people. Also I met a lot of colleagues which I didn’t see a long time and it was pleasant to see them again. As always I’ve uploaded my presentation on SlideShare: Upgrade on-premise sites from SP2010 to SP2013: problems and solutions. You may find details of my previous speeches here and here.

Update 2013-10-29: here is the video of my presentation: