Welcome to MSDN Blogs Sign in | Join | Help
Could not find stored procedure 'proc_ar_BumpCacheInvalidationCounter'

If you have a MOSS 2007 Standard Edition environment and you run a full Profile Import (either scheduled or manual) you can get the following message in the event log:

Error messages 7888 - "System.Data.SqlClient.SqlException: Could not find stored procedure 'proc_ar_BumpCacheInvalidationCounter'."

This is a known issue, the missing stored procedure is part of the BDC functionality, which is a MOSS 2007 Enterprise feature. The error messages can be safely ignored.

NB: The same error (or similar) can appear if you are trying to use BDC functionality on a MOSS 2007 standard environment. BDC is an enterprise functionality and need enterprise license of MOSS.

Access Denied when accessing local sites/webservices

Microsoft released MS09-014 and .Net Framework 3.5 SP1 which closed a vulnerability in NTLM authentication. If you’re browsing to your own machine, and the URL you’re browsing to doesn’t match the machine name, then NTLM authentication will fail. This affects calls to web sites and web services.

Possible solutions here: http://support.microsoft.com/kb/896861/en-us

 

From Larry Kuhn’s blog:

SharePoint Index Server Local Crawling affected by MS09-014 - KB 963027

How to expand InputFormTextBox

If you need to expand InputFormTextBox control and CssClass property seems to be not working, continue reading this post.

I’ve created an application page and I used an InputFormTextBox control to give users the possibility to write some html content. This is the code I used:

<wssawc:InputFormTextBox 
Title="My Field"
ID="myField"
Rows="15"
Runat="server"
TextMode="MultiLine"
RichText="true"
RichTextMode="FullHtml"/>

You can see the page rendering in the following picture:

image

As you can see, the control’s width is not at 100% of available space.

Trying to enlarge the control with style and CssClass attributes were unsuccessful. I made some investigations and I discovered that code rendered by the control simply ignores those attributes.

Looking at html generated by the control, I saw that it is rendered as two main element, a table element to display the toolbar and an iframe element for the html container. Both have a css class defined, ms-rtetoolbarmenu for the table (toolbar) and  ms-rtelong for the iframe (html container).

My solution to the problem was to override those classes with the following code

<style type="text/css"> 

table.ms-rtetoolbarmenu{ 
    width:100%;
} 

iframe.ms-rtelong{ 
    width:100%;
} 

</style> 

The page rendering after this modify was:

image

Hope this can help you.

Technorati Tag:
New release: SPDisposeCheck v1.3.1

A must-have for each Sharepoint developer. More info are available at Paul Andrew’s blog: http://blogs.msdn.com/pandrew/archive/2009/01/29/spdisposecheck-v1-3-1-is-released.aspx

How to hide content type choice control in edit forms

If you want the edit form of a particular list to don’t show some field, you can change the ContentType definition by setting ShowInEditForm=”FALSE” in corresponding FieldRef element.

If you want to do the same with Content Type field, the above hint simply don’t work.

To make it working you have to modify the rendering template of the edit form. To do this you have to create a new rendering template:

  1. copy the standard ListForm template from DefaultTemplates.ascx (ControlTemplate folder)
  2. create a new ascx file in the same folder and paste ListForm template
  3. change the template id to MyCustomForm
  4. remove the Sharepoint ContentTypeChoice control from the custom template

Then you have to associate the edit form to the custom template created above, to do this you can modify the content type definition inserting XmlDocuments tag under ContentType tag like in the following example:

<XmlDocuments>
  <XmlDocument 
NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms"> <FormTemplates
xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms"> <Display>ListForm</Display> <Edit>MyCustomForm</Edit> <New>ListForm</New> </FormTemplates> </XmlDocument> </XmlDocuments>

If you don’t have content type you can change the list definition schema by using the following code:

<Forms>
  <Form Type="DisplayForm" 
Url="DispForm.aspx"
SetupPath="pages\form.aspx"
WebPartZoneID="Main" /> <Form Type="EditForm"
Url="EditForm.aspx"
SetupPath="pages\form.aspx"
Template="MyCustomForm"
WebPartZoneID="Main" /> <Form Type="NewForm"
Url="NewForm.aspx"
SetupPath="pages\form.aspx"
WebPartZoneID="Main" /> </Forms>

HTH
Dario

Technorati Tag: ,
User Information Page (Userdisp.aspx vs person.aspx)

I hope with this post to clarify why in Sharepoint the User Information Page is rendered sometimes with userdisp.aspx and sometimes with person.aspx.

In WSS, when you click on a profile link you are redirected to the User Information Page used by WSS to display WSS profile informations, this page is userdisp.aspx and is located in the same web.

In MOSS (with profile services enabled), instead, when you click on a profile link you are redirected to a different User Information Page, person.aspx. This page is the page showing the public profile of a user and is located under mysite site collection.

Sometimes happens that in MOSS (with profile services enabled), when you click on a profile link you are redirected to userdisp.aspx instead of person.aspx and this page doesn’t permit you to change user profile attributes. I will give you in a moment a reason for this behaviour.

When you are in MOSS and click on a profile link, you are always redirected to userdisp.aspx. This page loads ProfileRedirect control which uses MySiteRedirectionUserControl to redirect to public profile page on mysite. For security reasons, this redirection is made only if the public profile page url is safe.

What does it mean safe? Ok, right question!

The following URLs are considered safe in redirection:

  1. Same host name as the original URL (portal at http://mycompany:80, and my site under http://mycompany:8080).
  2. The URL to be redirected is a Portal URL. That is, if we set Portal site connection (from site actions -> site settings -> Portal site connection) to be
    http://mysite.[hostheader], http://mysite... will then be considered as a safe URL.
  3. Loop back addresses like http://localhost, http://127.0.0.1.

HTH

Dario

Technorati Tag:
How to show Attachments with DataFormWebPart

If you are using DataFormWebPart and you need to add the list of attachments to the output you have to modify the XSLT to use the AttachmentsField control.

If you simply use  

<xsl:value-of select="@Attachments"/>

the result displayed will be a boolean (Yes/No) value. If you want to display the list of attachments with corresponding links you must use AttachmentsField control as described below. This control contains the logic needed to get the attachments and render the list with links.

First of all, locate the template with name dvt_1 and add the html code to insert a new column header like in the following example:

    <xsl:template name="dvt_1">
        <xsl:variable name="dvt_StyleName">Table</xsl:variable>
        <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row"/>
        <table border="0" width="100%" cellpadding="2" cellspacing="0">
            <tr valign="top">
                <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
                    <th class="ms-vh" width="1%" nowrap="nowrap"></th>
                </xsl:if>
                <th class="ms-vh" nowrap="nowrap">Title</th>
                <th class="ms-vh" nowrap="nowrap">Author</th>
                <th class="ms-vh" nowrap="nowrap">Modified</th>
                <th class="ms-vh" nowrap="nowrap">Attachments</th>
            </tr>
            <xsl:call-template name="dvt_1.body">
                <xsl:with-param name="Rows" select="$Rows"/>
            </xsl:call-template>
        </table>
    </xsl:template>

Now, locate the dvt_1.rowview template and add a new column with the AttachmentsField control:

<xsl:template name="dvt_1.rowview">
  <tr>
      <xsl:if test="position() mod 2 = 1">
          <xsl:attribute name="class">ms-alternating</xsl:attribute>
      </xsl:if>
      <xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
          <td class="ms-vb" width="1%" nowrap="nowrap">
              <span ddwrt:amkeyfield="ID" 
ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))"
ddwrt:ammode="view">
</
span> </td> </xsl:if> <td class="ms-vb"> <xsl:value-of select="@Title"/> </td> <td class="ms-vb"> <xsl:value-of select="@Editor" disable-output-escaping="yes"/> </td> <td class="ms-vb"> <xsl:value-of select="ddwrt:FormatDate(string(@Modified), 1040, 5)"/> </td> <td class="ms-vb"> <xsl:element name="SharePoint:AttachmentsField"> <xsl:attribute name="runat">server</xsl:attribute> <xsl:attribute name="ListId">
{D2C70ED5-8551-446D-B0CF-AC4B30387CF0}
</xsl:attribute> <xsl:attribute name="FieldName">Attachments</xsl:attribute> <xsl:attribute name="ControlMode">Display</xsl:attribute> <xsl:attribute name="Visible">true</xsl:attribute> <xsl:attribute name="ItemId">
<xsl:value-of select="@ID"/>
</
xsl:attribute> </xsl:element> </td> </tr> </xsl:template>

Important: you must change the value of ListId attribute with your list id!

HTH

Dario

Technorati Tag: ,
Plan for Global My Sites and User Profiles

[Updated on 2009-10-11 to include link to User Profile Replication Engine] 

If you have multiple farms (or simply one farm with two or more SSPs) and you want to set-up User Profiles and My Sites that are shared between SSPs, this post is for you.

Introduction and Sample Scenario

Let me describe a sample scenario with geographically distributed farms. In this scenario, users work in different regions, each of which uses a different SSP. Some users have to collaborate across regions, and must have access to multiple SSPs. This is particularly common if an employee in a global deployment moves between geographic locations.

image

Suppose that, as usually, users of each farm are configured in the same forest.

If you want to give users the possibility to see other users’ profiles you have to configure in each farm the import of profiles from Active Directory and if you want that users in a region can see profile of users of other regions you have to import all users profiles in each farm.

This works well and in each farm you can see all users details but what happen if you want to give users the possibility to update their details (like skills, blog site and so on)? Let me show you an example: MyLinks. MyUser1 is browsing a site collection located in Farm 1 and adds a shortcut to a page with MyLinks OOB functionality. This link is recorded in a property of the user profile on SSP1. If the same user MyUser1 goes to a different site collection hosted on Farm 2 and looks at the list of his links he cannot find the previous added link on Farm 1. This happens because of Farm 2 is using a different SSP and user profiles are not synchronized between SSPs.

We have a similar behavior with My sites. Each SSP hosts My Sites, so if a user click on MySite link from a site on Farm 1 he is redirected to the MySite hosted on SSP1 but if the same user click on MySite link from a site on Farm 2 he is redirected to a different MySite hosted on SSP2.

Ok, it seems quite bad but… MOSS has My Site Host Locations! If you don’t know what host locations are, you can read the following two paragraphs (from technet).

My Site host locations

As the name says, a My Site host location is the location where My Sites reside. A My Site host location is created automatically when a Shared Services Provider (SSP) is created. The host location is created in its own site collection on the default Web application, and all personal sites are stored in that location. In most scenarios, this is the only My Site host location for the entire deployment of Microsoft Office SharePoint Server 2007. Users can view My Sites if the SSP for the My Site host location imports their user profile information from directory services, and only if they have the Create personal site permission enabled. Individual personal sites are created when individual users click the My Site link on the top link bar of the site.

Managing multiple My Site host locations over multiple SSPs

In some cases, like our scenario, users can be members of two or more sites that use different SSPs and different My Site host locations. In that case, by default, the user can see the My Sites in the host location used for the SSP of the current site. My Sites in other host locations cannot be seen, and the personalization features of those sites cannot be used. This configuration results in an unpredictable My Site experience. Each user's My Site changes depending upon the site, and the My Sites of other users are not reliably available on each site.

To avoid this situation, it is usually a good practice to limit each user to one SSP. However, in our scenario, this is not possible and it is a good idea to think through the reasons for multiple SSPs and then create a predictable experience for My Sites and personalized content.

To enable users to view My Sites and use personal features on multiple host locations, each host location must enable support for global deployments on the My Site Settings page. This makes personalized content on each host location available across SSPs, but only if the host location is trusted by an SSP. Each SSP has a list of trusted My Site host locations links. Each link can be targeted so that only users in selected audiences can view My Sites in a particular host location. Profile information for all targeted users is replicated to each SSP and is available to all sites on the SSP. My Site host locations are used by each SSP in the order of the trusted My Site host locations list. If a user is a member of an audience targeted by one host location link, then that My Site host location is used for that SSP and the later host locations are ignored. This results in one set of personalized content for each user being made available to all targeted users in each SSP.

Configuration and Interface Behavior

Coming back to our sample scenario, to appropriately configure My Site host locations we have to enable on each SSP support for global deployments and define for each SSP the following host locations:

  • Host Location 1 (Region 1), targeted to audience “Users of Region 1”
  • Host Location 2 (Region 2), targeted to audience “Users of Region 2”
  • Host Location 3 (Region 3), targeted to audience “Users of Region 3”

After that the My Site link in each site of each farm will point to the My Site in the SSP where the user belongs. Furthermore, the “Add Link” and “Manage Links” links are targeted to the same (correct) SSP. All other functionalities that show profile information (such as the list of links defined by the user) are instead targeted to the SSP which is related to the current site. This underlines the needs of a profile replication mechanism (described later in this post).

 

This picture illustrates MOSS behavior for a user belonging to Region 2:

clip_image002

The following picture shows the option to be enabled in My Site Settings page of each SSP

clip_image002[10]

This picture shows the Add new My Sit Host Location form:

clip_image004

Replication of User Profiles

To keep MOSS 2007 profile data across three worldwide regions consistent for People Search and Audiences targeting we need a Geo Replication mechanism.

Each farm hosts only a subset of user’s MySites/Profiles and can be consider as “Master” on this subset of users for the other farms. So the replication engine should replicate user profiles from each Master farm versus other farms.

Microsoft has released the Sharepoint Administration Toolkit which include User Profile Replication Engine, a tool that does replication of user profiles.

The replication mechanism can be represented by this picture:

image

Unified Search Experience with MOSS

I’d like to summarize all configurations needed to obtain a Unified Search Experience for end users, obviously with MOSS as Enterprise Search Engine J. With “Unified Search Experience” I mean the possibility to search for enterprise content not only from the Search Intranet Portal but also from client applications like Office Applications, Windows Search and IE.

First of all you need to discover the correct URLs to use as search engines/providers.

Open your Search Centre (for example http://search.litewareinc.com/) and search for something using the default scope. You will be redirect probably to a page like http://search.litewareinc.com/Pages/results.aspx?k=SOMETHING, write down this URL.

Now change the scope (if you have defined scopes, obviously) and perform the search again. The URL should be http://search.litewareinc.com/Pages/results.aspx?k=SOMETHING&s=MYSCOPE, write down this URL also.

(NB: You should write down an URL for each scope you have defined)

Don’t forget to search for people and write down the corresponding URL, it should looks like http://search.litewareinc.com/Pages/peopleresults.aspx?k=SOMETHING.

The last URL you need is the Search Web Service URL: http://search.litewareinc.com/_vti_bin/search.asmx

At the end you should have something like this:

  • Search with Web Site
    • http://search.litewareinc.com/Pages/results.aspx?k=SOMETHING
    • http://search.litewareinc.com/Pages/results.aspx?k=SOMETHING&s=MYSCOPE1
    • http://search.litewareinc.com/Pages/results.aspx?k=SOMETHING&s=MYSCOPE2
    • http://search.litewareinc.com/Pages/peopleresults.aspx?k=SOMETHING
  • Search with Web Service
    • http://search.litewareinc.com/_vti_bin/search.asmx

Note that MYSCOPE, MYSCOPE1 and MYSCOPE2 are your scopes and are fixed, instead you will have to replace the word SOMETHING with $w or TEST depending on the configuration you are doing (described below).

Now take a look at how to configure this Unified Search Experience in different products/technologies.

 

Configuring Windows Search 4.0 (beta) on Windows XP

You can customize the behavior of WS4.0 by adding a new button in Search Bar to search for the “Primary Intranet Search Location”. Besides you can also add other “Secondary Intranet Search Locations” that will be visible in Search Companion location selection menu.

To perform this configuration, you have to work with local computer policies (you can also create group policy objects to manage this settings centrally) following the steps below:

  • Run gpedit.msc
  • Right click on Administrative Templates under Computer Configuration and select “Add/Remove templates…
  • Verify that Search.adm is listed otherwise add it from c:\windows\inf
  • Now locate “Add Primary Intranet Search Location” under “Windows Component\Search
  • Right click --> properties
  • Enable it and specify the value with the sintax: name,url - for example you can use the default scope specifying this value: MyIntranet,http://search.litewareinc.com/Pages/results.aspx?k=$w
    Note that you must replace SOMETHING with $w
  • Apply the changes
  • Now Locate “Add Secondary Intranet Search Locations” and enable it specifying all other locations with the following sintax: name1,url1;name2,url2;name3,url3
  • Apply changes

After above steps you will be able to search in MOSS also within WS4.0 Search Bar and Search Companion.

Useful links:

Windows Search 4.0 Administrator's Guide
http://technet2.microsoft.com/windowsserver2008/en/library/f98696ed-6e3e-47b7-ab38-511439bce7ae1033.mspx?mfr=true

Group Policy for Windows Search
http://technet2.microsoft.com/windowsserver2008/en/library/c55e6003-8b70-4d5e-a0ce-55c25a35015a1033.mspx?mfr=true

 

Configuring Windows Vista Search
(from Mark Harrison’s post)

You can add an Intranet search location directly into Windows Vista Desktop. To perform this configuration, you have to work with local computer policies (you can also create group policy objects to manage this settings centrally) following the steps below:

  • Run gpedit.msc (requires elevation)
  • Locate “Custom Instant Search Internet Search Provider” under “User Configuration --> Administrative Templates --> Windows Components --> Instant Search
  • Right click --> properties
  • Enable it and specify a name (ex: Search MSWeb) and the url of the default scope (ex: http://search.litewareinc.com/Pages/results.aspx?k=$w)
    Note that you must replace SOMETHING with $w
  • Apply the changes
  • You must reboot or run gpupdate /force from an elevated prompt

Now you will find a new search location in Vista Search Window like the following

image

 

Configuring Office Research Task Pane

Both Office 2003 and Office 2007 include the Research Task Pane that permits to add external search services to be used for querying external content. This is accomplished by implementing a well defined contract that MOSS2007 exposes out of the box. In this case we will use the “Search with Web Service” URL defined above.

Open for example MS Word 2007 (in 2003 is quite similar), click on Review and then on Research: this will shows the Research Task Pane.

Now click on the “Research options” bottom link and then click the “Add services…” button.

Specify the address of your Web Service and follow the instructions.

Now you are able, inside Word, to search for content indexed by MOSS and the results will be displayed (grouped) together with results from other services.

This configuration automatically affects also other MS Office applications and also IE.

Configuring IE7

In IE7 you can add custom search providers which will be added to the search provider list available via Search Options (down arrow near search box and magnifying glass).

clip_image002

To do it, you have to click on “Find More Providers…” in the search Options Menu. It will display a web page in which you have to specify your Own Provider using the “Search with Web Site” URLs defined above. Don’t forget to replace the word SOMETHING with the word TEST. Click Install to add it to your provider list.

When you will have installed all URLs, you will be able to use IE7 search box to search for content inside the corresponding scope in MOSS simply by selecting it in Search Options Menu.

Rilasciato il Microsoft SharePoint Administration Toolkit 1.0

Il 30 Aprile è stato rilasciato il Microsoft SharePoint Administration Toolkit 1.0, un toolkit destinato agli amministratori di una farm SharePoint che fornisce loro due strumenti aggiuntivi:

  • Batch Site Manager
    Feature accessibile dalla pagina Application Management della Central Administration che permetterà di gestire e amministrare operazioni multiple inerenti la cancellazione, lo spostamento e il blocco (lock) di una o più Site Collection all'interno della stessa Web Application.
  • Alert Fixer
    Una nuova operazione (updatealert) di STSADM.EXE che dà la possibilità ad un amministratore, in seguito ad un cambio dell'indirizzo di una Web Application, di aggiornare l'URL della Web Application usato nelle email di alert.

Il toolkit è scaricabile qui (la versione x64 invece è scaricabile qui) ma consiglio vivamente di leggere il relativo White Paper che illustra anche alcuni aspetti dell'installazione e i requisiti per il corretto funzionamento.

"Impossibile caricare il flusso di lavoro" errore in Sharepoint Designer

Se anche a voi è capitato di non riuscire ad aprire o creare un nuovo workflow da Sharepoint Designer ottenendo il seguente errore:

image

allora la soluzione è quella di cancellare la cartella 12.x.x.xxxx presente sotto C:\Documents and Settings\<my user name>\Dati Applicazioni\Microsoft\SharePoint Designer\ProxyAssemblyCache

Incredibile ma vero. Per correttezza riporto il post in inglese che mi ha permesso di risolvere il problema presso il cliente.

“Failed to load the workflow” Error Message in SharePoint Designer - Scott's blog

Workflow sui sondaggi? Unsupported!

Ebbene si, è inutile che proviate a configurare il vostro bel workflow sulla lista di un sondaggio perché non potrà mai funzionare. Ho infatti trovato questa KB che lo sancisce:

The status of a workflow appears as "Failed to Start" when you try to start a workflow from a survey response in Windows SharePoint Services 3.0

Prima che trovassi la KB mi sono messo a cercare di capire come mai il mio semplice workflow non partiva dopo aver sottomesso la risposta ad un sondaggio. O meglio, cercava di partire e si arenava miseramente segnalando "Failed to Start".

Nei log ho trovato il seguente errore:

RunWorkflow: System.ArgumentException: Invalid field name. {ae069f25-3ac2-4256-b9c3-15dbc15da0e0}     at Microsoft.SharePoint.SPFieldCollection.GetFieldById(Guid fieldId, Boolean bThrowException)     at Microsoft.SharePoint.SPFieldCollection.get_Item(Guid id)     at Microsoft.SharePoint.SPListItem.get_Item(Guid fieldId)     at Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties..ctor(SPWorkflow workflow, Int32 runAsUserId, String associationData, String initiationData)     at Microsoft.SharePoint.Workflow.SPWinOEWSSService.MakeActivation(SPWorkflow workflow, SPWorkflowEvent e)     at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(Guid trackingId, SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut)     at Microsoft.SharePoint.Workflow.SP..

Giocando con il Reflector ho capito che il problema è dovuto al fatto che, durante l'attivazione del workflow, Sharepoint tenta di accedere al campo GUID (FieldID=ae069f25-3ac2-4256-b9c3-15dbc15da0e0) dell'item a cui è associata l'istanza del workflow ma a quanto pare gli item della lista di tipo sondaggio non hanno tale attributo! Ecco quindi perché non potrà mai funzionare e quindi perché viene dichiarato come Unsupported.

Ecco qualche dettaglio del codice disassemblato:

Il metodo MakeActivation dell'oggetto SPWinOEWSSService è:

internal static void MakeActivation(SPWorkflow workflow, SPWorkflowEvent e)
{
    e.IsActivation = true;
    e.EventType = typeof(ISharePointService).GUID;
    e.EventName = "OnWorkflowActivated";
    string associationData = workflow.ParentAssociation.AssociationData;
    string initiationData = null;
    if ((e.EventData != null) && (e.EventData.Length > 0))
    {
        initiationData = e.EventData[0] as string;
    }
    if (e.IsAutostart && (initiationData == null))
    {
        initiationData = associationData;
    }
    e.EventData = new object[] { workflow.InstanceId, 
new SPWorkflowActivationProperties(workflow,
e.RunAsUserId,
associationData,
initiationData)
}; }
Il costruttore di SPWorkflowActivationProperties è:
internal SPWorkflowActivationProperties(SPWorkflow workflow, 
int runAsUserId,
string associationData,
string initiationData) { this.m_itemId = -1; this.m_workflow = workflow; if (!this.SuperUserWorkflow) { throw new ArgumentException(); } this.m_associationData = associationData; this.m_initiationData = initiationData; this.m_workflowId = this.Workflow.InstanceId; this.m_itemId = this.Item.ID; this.m_listId = this.List.ID; this.m_taskListId = this.Workflow.TaskListId; this.m_histListId = this.Workflow.HistoryListId; this.m_templateName = this.Workflow.ParentAssociation.Name; this.m_itemGuid = new Guid((string) this.Item[SPBuiltInFieldId.GUID]); this.m_webId = this.Web.ID; this.m_siteId = this.Site.ID; if (runAsUserId != this.OriginatorUser.ID) { throw new ArgumentException(); } this.m_originator = this.OriginatorUser.LoginName; this.m_originatorEmail = this.OriginatorUser.Email; this.m_siteUrl = this.Site.Url; this.m_webUrl = this.Web.Url; this.m_itemUrl = this.Item.Url; this.m_listUrl = this.List.RootFolderUrl; this.m_histListUrl = this.HistoryList.RootFolderUrl; this.m_taskListUrl = this.TaskList.RootFolderUrl; }
Da cui si evince il tentativo di accesso al field indicato da SPBuiltInFieldId.GUID che infatti è quello indicato nei log:
static SPBuiltInFieldId()
{
    [...]
    GUID = new Guid("{ae069f25-3ac2-4256-b9c3-15dbc15da0e0}");
    [...] 
}

HTH

Realizzare un controllo con anteprima per il campo PublishingRollupImage in MOSS 2007

Il campo PublishingRollupImage, aggiunto con la Publishing Feature di MOSS 2007, permette di specificare l'icona/immagine che è possibile visualizzare nelle ContentByQueryWebPart. Tipicamente viene inserito nell'EditPanel nei Page Layout in modo che i redattori possano, in fase di editing di una pagina, navigare nelle library del sito per scegliere l'immagine da associare alla pagina che stanno creando.

Può capitare che non si voglia dare l'onere ai redattori di trovare l'immagine navigando nelle liste del sito ma si voglia fornire loro un elenco testuale di possibili scelte visualizzando magari un anteprima dell'immagine relativa. Se ad esempio abbiamo creato un Page Layout per il ContentType Notizia potremmo voler permettere ai redattori di scegliere immagini differenti a seconda del tipo di notizia (importanza, rating, genere).

Vediamo ora un esempio di come si possa realizzare una soluzione al problema esposto sopra. Per prima cosa dobbiamo definire l'interfaccia del controllo che verrà visualizzato nel PL e per farlo creeremo un controllo ASCX con il seguente codice:

<%@ Control Language="C#" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, 
PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"
%>
<SharePoint:RenderingTemplate ID="PageTypeFieldControl" runat="server">
    <Template>
    <asp:Table runat="server" id="tblPageTypeControl">
    <asp:TableRow>
    <asp:TableCell>
        <asp:DropDownList ID="ddlPageTypes" runat="server" >
            <asp:ListItem Value="Normal.jpg" Selected="True">Normale</asp:ListItem>
            <asp:ListItem Value="Important.jpg">Importante</asp:ListItem>
            <asp:ListItem Value="Urgent.jpg">Molto Urgente</asp:ListItem>
        </asp:DropDownList>
    </asp:TableCell>
    <asp:TableCell><asp:Image ID="imgPreview" runat="server" /></asp:TableCell>
    </asp:TableRow>
    </asp:Table>
    </Template>
</SharePoint:RenderingTemplate>

Come vedete si tratta semplicemente di una tabella con all'interno una DropDownList contenente l'elenco delle immagini ed un oggetto Image che sarà utilizzato per l'anteprima. Tale file dovrà essere salvato nella cartella %program files%\Common Files\Microsoft Shared\Web Server Extensions\12\template\controltemplates\

NB: Questo è solo un esempio, sarebbe sicuramente meglio rendere dinamico l'elenco della DropDownList.

Quello che abbiamo fatto è creare un controllo costituito da un RenderingTemplate a cui abbiamo scelto arbitrariamente di assegnare l'identificativo PageTypeFieldControl. A questo punto dobbiamo creare il controllo vero e proprio che verrà renderizzato tramite il suddetto RenderingTemplate.
Innanzitutto creiamo un progetto di tipo Library e facciamo ereditare la classe da BaseFieldControl:

using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Publishing.Fields;
using Microsoft.SharePoint.Publishing.WebControls;
using UI = System.Web.UI.WebControls;
using System.ComponentModel;
using Microsoft.SharePoint;
    public class PageTypeFieldControl : BaseFieldControl
    {
protected UI.DropDownList ddlPageTypes; protected UI.Image imgPreview; protected UI.Table tblPageTypeControl; }

 Poi dobbiamo associare il RenderingTemplate alla classe facendo il seguente override:

        protected override string DefaultTemplateName
        {
            get
            {
                return "PageTypeFieldControl";
            }
        }

Per evitare di specificare all'interno del controllo ascx il path della lista/cartella contenente le immagini prevediamo una proprietà dell'oggetto da utilizzare allo scopo:

        private string _ImageFolder="";

        [Browsable(true)]
        public string ImageFolder
        {
            get { return _ImageFolder; }
            set { _ImageFolder = value; }
        }

A questo punto facciamo un override del metodo CreateChildControls per impostare delle personalizzazioni agli oggetti come ad esempio i valori iniziali, i fogli di stile CSS e gli eventHandler per la DropDownList.

        protected override void CreateChildControls()
        {
            if (Field == null) return;

            base.CreateChildControls();

            if (ControlMode == SPControlMode.Display)
                return;

            //Tabella HTML contenitrice
            tblPageTypeControl = (UI.Table)this.Controls[0].FindControl(
"tblPageTypeControl"); if (tblPageTypeControl == null) throw new NullReferenceException(
"tblPageTypeControl is null. Corrupted PageTypeFieldControl."); tblPageTypeControl.TabIndex = TabIndex; tblPageTypeControl.CssClass = CssClass; //IMG HTML di preview imgPreview = (UI.Image)this.Controls[0].FindControl("imgPreview"); if (imgPreview == null) throw new NullReferenceException("imgPreview
is null. Corrupted PageTypeFieldControl."
); imgPreview.TabIndex = TabIndex; imgPreview.CssClass = CssClass; imgPreview.ToolTip = "Anteprima per " + Field.Title; //DropDown List ddlPageTypes = (UI.DropDownList)this.Controls[0].FindControl(
"ddlPageTypes"); if (ddlPageTypes == null) throw new NullReferenceException(
"ddlPageTypes is null. Corrupted PageTypeFieldControl."); ddlPageTypes.TabIndex = TabIndex; ddlPageTypes.CssClass = CssClass; ddlPageTypes.ToolTip = "Scelta per " + Field.Title; ddlPageTypes.AutoPostBack = true; ddlPageTypes.SelectedIndexChanged += new EventHandler(
ddlPageTypes_SelectedIndexChanged); if (ControlMode == SPControlMode.New || imgPreview.ImageUrl=="") { ddlPageTypes.SelectedIndex = 0; imgPreview.ImageUrl = ImageFolder + ddlPageTypes.SelectedValue; } } void ddlPageTypes_SelectedIndexChanged(object sender, EventArgs e) { imgPreview.ImageUrl = ImageFolder + ddlPageTypes.SelectedValue; }

Volendo possiamo anche fare un override del metodo Focus() per scegliere quale controllo costituente deve avere il focus:

        public override void Focus()
        {
            EnsureChildControls();
            if (ControlMode == SPControlMode.Display)
                return;
            ddlPageTypes.Focus();
        }

Per far sì che il valore del field associato al nostro controllo sia visualizzato e salvato tramite il controllo stesso dobbiamo fare il seguente override:

        public override object Value
        {
            get
            {
                EnsureChildControls();
                if (ControlMode == SPControlMode.Display)
                    return null;

                ImageFieldValue ImageValue = new ImageFieldValue();
                try
                {
                    ImageValue.ImageUrl = ImagesFolder + ddlPageTypes.SelectedValue;
                }catch(Exception ex)
                {
                    ImageValue.ImageUrl="";
                }
                return ImageValue;
            }
            set
            {
                EnsureChildControls();
                ImageFieldValue ImageValue = value as ImageFieldValue;
                string url = ImageValue.ImageUrl;
                if(url!=string.Empty)
                    url = url.Substring(url.LastIndexOf("/")+1);
                ddlPageTypes.SelectedValue = url;
                imgPreview.ImageUrl = ImageValue.ImageUrl;
            }
        }

A questo punto il componente è ultimato. Occorre quindi compilarlo, registrarlo in GAC ed inserirlo tra i SafeControls di Sharepoint.

 Per utilizzarlo sarà sufficiente inserire nel PageLayout l'apposto TagPrefix

<%@ Register Tagprefix="MyWebControls" Namespace="MyNamespace"
Assembly="MyAssembly, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=b39c38c41d5734c2"
%>

e la relativa dichiarazione:

<MyWebControls:PageTypeFieldControl id="myPageType" FieldName="PublishingRollupImage"
runat="server" ImageFolder="" CssClass="dateLine">
</MyWebControls:PageTypeFieldControl>

HTH

Come modificare il font standard dei campi INPUT disabilitati

E' sicuramente una banalità ma può servire a risparmiare tempo...

In IE, contrariamente ad altri browser, non è possibile modificare il font standard dei campi INPUT disabilitati (Enabled="false") e quindi è inutile cercare nella sintassi dei CSS un comando adatto allo scopo. Non è quindi possibile cambiare il colore del testo in un campo disabilitato.

Per ovviare al problema io utilizzo l'evento onFocus ed i css per ottenere un campo che si comporti come se fosse disabilitato ma con la possibilità di personalizzarne l'aspetto. Ecco un esempio:

<input name="MyTextbox" value="MyValue" type="text" 
class="locked" onfocus="blur();" />

dove ad esempio la classe "locked" è così definita:

.locked
{
    cursor:default;
    color:Navy;
    background-color: #ccffff;
}

In particolare:

  • imposto onfocus="blur();" per ottenere che il controllo non mantenga mai il focus; quindi sarà impossibile modificarne il contenuto
  • poi, con cursor:default nel css, imposto il tipo di cursore (per evitare che appaia la classica I di modifica e che l'utente consideri il campo come editabile)

A questo punto avrà effetto anche il colore del font nel foglio di stile (color:Navy;) come desiderato.

HTH

Nick’s Exchange and Scripting Blog: Managing Exchange 2007 Recipients with C#

Mentre stavo per realizzare l'ennesima applicazione web che interagiva con Exchange attraverso la libreria CDOEXM mi sono accorto che con Exchange 2007 CDOEXM è stato cassato... Allora mi sono fatto un giro sul web per scoprire quale nuova libreria dovessi utilizzare per creare una mailbox e mi si è aperto un mondo!

Mi ero ripromesso di dare un'occhiata alla nuova Windows PowerShell ma ho sempre rimandato, adesso però è arrivato il momento. CDOEXM e WMI sono stati sostituiti in Exchange 2007 dall'Exchange Management Shell, uno SnapIn per PowerShell.

Vi consiglio caldamente di leggere il post di Nick Smith (in inglese):

Nick’s Exchange and Scripting Blog: Managing Exchange 2007 Recipients with C#

è molto utile e fornisce un wrapper in C# semplice da utilizzare. Serve a poco, però, senza un'infarinatura di base dell'Exchange Management Shell:

Mstehle's Introduction to Exchange Powershell Automation
Part 1: http://blogs.msdn.com/mstehle/archive/2007/01/25/fyi-introduction-to-exchange-powershell-automation-part-1.aspx
Part 2: http://blogs.msdn.com/mstehle/archive/2007/01/25/outbox-introduction-to-exchange-powershell-automation-part-2.aspx

More Posts Next page »
Page view tracker