Monday, March 25, 2013

Site Feed Web Part Newsfeed Title

If you were ever wondering how do you change "Newsfeed" title when using SiteFeed web part... It is a predefined resource located in profilebrowserscriptres.resx and profilebrowserscriptres.en-US.resx (depends on your locale).


  <data name="SiteFeedTitleName" xml:space="preserve">
    <value>Newsfeed</value>
    
  </data>
While you can tweak it, it is highly not recommended, as changes to Microsoft files, located in 15 HIVE could be overwritten during service pack deployment, migrations, etc.

Thursday, March 21, 2013

Setting Custom ListFormWebPart Parameters in List Definition

In order to set custom ListFormWebPart parameters when defining list definition schema, you need to modify Form tag in schema.xml. Please refer to the following sample, used to add CSRRenderMode property to ListFormWebPart and set it to ServerRender:

<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False">
    <WebParts>
      <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="1">
        <![CDATA[
<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">
  <Assembly>Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, 
         PublicKeyToken=71e9bce111e9429c</Assembly>                         
  <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
  <PageType>PAGE_NEWFORM</PageType>
  <CSRRenderMode xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">ServerRender</CSRRenderMode>

</WebPart>]]>
      </AllUsersWebPart>
    </WebParts>
</Form>

You can change Microsoft.SharePoint assembly reference to 14.0.0.0 or 12.0.0.0 to use it with SharePoint 2010 or SharePoint 2007 respectfully.

SharePoint 2013 Event Receiver Redirect

It used to be a standard practice to use redirect in event receivers in SharePoint 2010 and SharePoint 2007. SharePoint 2013 has some changes in this functionality.

Redirect Option Availability

No redirect options available for ItemAdded, ItemUpdated and ItemDeleted.

Some redirect options available for ItemAdding, ItemUpdating and ItemDeleting. They are only available when the form, which initiates an event, is being rendered in CSRRenderMode.ServerRender mode. Otherwise list forms are committed through asynchronous XmlHttpRequests, and redirect options are not available.

CancelWithRedirectUrl - DOES NOT WORK

The following code does function:

properties.RedirectUrl = "http://www.google.com";
properties.Status = SPEventReceiverStatus.CancelWithRedirectUrl;
Compiler is issuing the following warning:
'Microsoft.SharePoint.SPEventReceiverStatus.CancelWithRedirectUrl' is obsolete: '"Default list forms are committed through asynchronous XmlHttpRequests, so redirect urls specified in this way aren't followed by default. In order to force a list form to follow a cancelation redirect url, set the list form web part's CSRRenderMode property to CSRRenderMode.ServerRender"'. If you need to figure out how to set CSRRenderMode.ServerRender property for the form automatically (in list definition), please refer to my other blog post

SPUtility.Redirect - DOES NOT WORK

SPUtility.Redirect does not work in Event Receivers any more. It actually throws an exception. The reason - SPUtility.Redirect relies on HttpContext.Current, which does not exist at that point of execution. Tested with different CSRRenderMode settings.

[SubsetCallableExcludeMember(SubsetCallableExcludeMemberType.UnsupportedExternalType)]
public static bool Redirect(string url, SPRedirectFlags flags, HttpContext context, string queryString)
{
    string urlRedirect = null;
    bool flag = DetermineRedirectUrl(url, flags, context, queryString, out urlRedirect);
    if (flag)
    {
        bool flag2 = SPRedirectFlags.DoNotEndResponse == (flags & SPRedirectFlags.DoNotEndResponse);
        bool flag3 = DeltaPage.IsDeltaRedirectDisabled(context);
        if (!flag3 && DeltaPage.IsRenderingDelta(context))
        {
            DeltaPage handler = context.Handler as DeltaPage;
            if (handler != null)
            {
                handler.Redirect(context, urlRedirect, !flag2);
            }
            return flag;
        }
        bool flag4 = ((!flag3 && IsMDSEnabled(context)) && (!IsDialogUrl(urlRedirect) && IsBrowserRequest(context.Request))) && (SPRedirectFlags.AttemptMDSNavigate == (flags & SPRedirectFlags.AttemptMDSNavigate));
        bool flag5 = false;
        if (flag4)
        {
            flag5 = DeltaPage.AttemptMDSRedirect(context, urlRedirect, !flag2);
        }
        if (flag4 && flag5)
        {
            return flag;
        }
        SPLongOperation currentLongOperation = SPLongOperation.CurrentLongOperation;
        if (currentLongOperation != null)
        {
            currentLongOperation.End(url, flags, context, queryString);
            return flag;
        }
        if (Utility.IsClientQuery(context) && !Utility.IsRedirectAllowed(context))
        {
            RedirectException exception = new RedirectException(urlRedirect);
            context.Items[typeof(RedirectException)] = exception;
            throw exception;
        }
        try
        {
            context.Response.Redirect(urlRedirect, !flag2);
        }
        catch (Exception exception2)
        {
            if ((exception2 is ThreadAbortException) && !flag2)
            {
                throw;
            }
            ULS.SendTraceTag(0x62613371, ULSCat.msoulscat_WSS_Runtime, ULSTraceLevel.Medium, "Redirect to {0} failed. Exception: {1}", new object[] { url, exception2.ToString() });
        }
    }
    return flag;
}


internal static bool IsMDSEnabled(HttpContext ctx)
{
    return (((((ctx != null) && !DeltaPage.IsStartPage) && (!SPMobileUtility.IsMobilePageRequest(ctx, ctx.Request.Browser) && (ContextCompatibilityLevel >= 15))) && ((SPContext.Current != null) && (SPContext.Current.Web != null))) && SPContext.Current.Web.EnableMinimalDownload);
}


public static bool IsStartPage
{
    get
    {
        return IsMDSStartPageUrl(SPAlternateUrl.ContextUri.AbsolutePath);
    }
}


public static Uri ContextUri
{
    get
    {
        return GetContextUri(HttpContext.Current); //Here it throws an exception
    }
}

WORKING SOLUTION:

_currentContext.Response.Redirect

_currentContext.Response.Redirect does work though (IMPORTANT: Only when the form, which initiates an event, is being rendered in CSRRenderMode.ServerRender mode.) You can use the following sample:

public class TestEventHandler : SPItemEventReceiver
 {
  private readonly HttpContext _currentContext;
  public TestEventHandler()
  {
   _currentContext = HttpContext.Current;
  }
  // Methods
  public override void ItemAdding(SPItemEventProperties properties)
  {
   var url = new StringBuilder("test.aspx");
   string urlRedirect = null;
   bool flag = SPUtility.DetermineRedirectUrl(url.ToString(), SPRedirectFlags.RelativeToLayoutsPage, _currentContext, null, out urlRedirect);
   _currentContext.Response.Redirect(urlRedirect, true);
  }
 }

Wednesday, March 20, 2013

SharePoint 2013 CAML SPSiteDataQuery Lookup Field Bug

When using CAML and SPSiteDataQuery, and including a lookup field in ViewFields, you have to make sure this field is used in Query as well (i.e. in OrderBy). Otherwise it would not show up in your result dataset. This happens in SharePoint 2013 (15.0.4420.1017). Same query in 2010 and 2007 produces result dataset without the need to include the field in query. Looks like a bug in SharePoint 2013.

Wednesday, March 6, 2013

SharePoint 2013 Site Definition Migration

SharePoint 2013 site definition requires "<!-- _lcid="1033" _version="15.0.4420" _dal="1" -->" to be present in site definition template file (with respect to your regional settings obviously). It would not show up otherwise. It was not a requirement before, so make sure you have it updated/added when migrating your solution from 2007/2010.

Friday, February 8, 2013

Additional SharePoint 2013 App Part Tokens

There have been a very interesting article at SharePoint Developer Support Team Blog. It discusses editMode parameter, and also mentions WPID parameter in the code sample. This got me into researching this matter.

So far we had two MSDN articles, discussing tokens: URL strings and tokens in apps for SharePoint and URLs and tokens in SharePoint 2013.

They both lack a few important App Part tokens (parameters). Here they are:

  • editMode - has two possible values: 1 or 0. 1 means the web part (not Page) is currently in Edit Mode.
  • WPID - represents a WebPart.ID (sample value is "g_f5ac6d08_5b6f_41ea_90d1_0cc8a030061c").
  • WPQ - represents a WebPart.ClientID (sample value is "ctl00_ctl33_g_f4a94a49_ce63_4c7f_ba05_884b17132672").
  • WebLocaleId - represents a web.Language.ToString(CultureInfo.InvariantCulture) (sample value is "1033"), which is a Language Id.

You can use all those tokens in the URL, the same way as you use custom properties, without the need of adding actual properties. All tokens are case sensitive.

<ClientWebPart Name="ClientWebPart" Title="TestAppPart" Description="TestAppPart" DefaultWidth="600" DefaultHeight="300">
  
  <Content Type="html" Src="~appWebUrl/Pages/DemoPage.aspx?{StandardTokens}&amp;wpId=_WPID_&amp;editmode=_editMode_&amp;wpq=_WPQ_&amp;weblocaleId=_WebLocaleId_" />

  <Properties>
  </Properties>

</ClientWebPart>

There are a few additional tokens (parameters) not allowed for the app parts, but allowed when rendering XmlWebPart, PageViewerWebPart, ImageWebPart, DataViewWebPart and DataFormWebPart. I did not try them out though, so your feedback on their usage is welcome. Here they are:

  • LogonUser - represents a context.Request.ServerVariables["LOGON_USER"].
  • WPR - represents a Web Part Resource Path : (web.Url + "/" + web.TypeCache[type, web.IsAppWeb, false].WebRelativeClassResourcePath).
  • WPSRR - represents a Web Part Server Relative Resource Path : web.GetServerRelativeUrlFromUrl(web.TypeCache[type, web.IsAppWeb, false].WebRelativeClassResourcePath).

Wednesday, January 9, 2013

SharePoint SPSiteDataQuery DateTime Results Timezone

When working with SPSiteDataQuery keep in mind that all DateTime results are being returned either in current user profile regional settings timezone, or under root web regional settings timezone, depending on the settings. It will ignore all the sub web regional settings.