tag:blogger.com,1999:blog-53307346415729188922024-03-13T21:35:36.350-07:00Discovering SharePointJasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.comBlogger13125tag:blogger.com,1999:blog-5330734641572918892.post-45493750190718663152009-04-20T12:15:00.000-07:002009-04-20T12:19:14.807-07:00Moving to Abstractions-R-UsDue to our inability to make a SharePoint server work sufficiently, my company is no longer going to be using SharePoint, and I am no longer doing SharePoint development. I will continue blogging at <a href="http://abstractions-r-us.blogspot.com/">http://abstractions-r-us.blogspot.com/</a>.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-45890693396541279782008-11-18T06:10:00.001-08:002008-11-18T06:14:58.899-08:00Displaying correct user namesIn looking for an answer to <a href="http://discoveringsharepoint.blogspot.com/2008/11/display-names-are-screwed.html">our current dilemma</a>, I found many people are struggling with a problem we already solved, so here I share the solution.<br /><br />A common issue is that, even though display names in AD may be "FirstName LastName", they are not pulled into SharePoint, letting display names in SP default to "Domain\Username".<br /><br />The solution: Make sure the account used to import users is trusted by the domain (controller). You have to give it perms to access things like display name and email address.<br /><br />Take our former situation for example. Here, we have Domain-A (which has the DC which most user accounts are on) and Domain-B (where our MOSS servers are). Domain-B trusts Domain-A, but not the other way around. All MOSS-related system accounts were originally on Domain-B... So, they would pass credentials on to the DC on Domain-A (because B trusts A), but could not get display names, email addresses, etc. from the DC (because A does not trust B).<br /><br />So we had to create an account on Domain-A to query AD. We then set said account as the one that imports profiles:<br /><ol><li>In Shared Services Administration, go to User profiles and properties -> Configure Profile Import.</li><li> Under Default Access Account, we input credentials for our Domain-A account with read access on AD. Problem solved, on to the next one!</li></ol>Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-64257045870740806512008-11-14T11:52:00.001-08:002008-11-14T11:53:15.868-08:00Display Names are Screwed!One day, the display names on our production SharePoint server were all truncated to the first 3 characters! Egad! No one knows why or how this happened.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-57640168230882436592008-09-30T13:20:00.000-07:002008-09-30T14:19:36.367-07:00Disabling Impersonation Without Breaking Search CrawlerA common workaround for authentication issues on some SP apps is to disable impersonation in the Web.config file corresponding to the SP app's IIS site. Unfortunately, doing so makes the site inaccessible to the search crawler.<br /><br />However, <a href="http://iamabadprogrammer.blogspot.com/">iamabadprogrammer</a> has written a <a href="http://iamabadprogrammer.blogspot.com/2008/03/sharepoint-search-crawl-failed.html">post</a> describing a way to disable impersonation without disabling or breaking the search crawler. Here's how I made this work:<br /><ol><li>In Central Administration, go to Application Management > Create or Extend Web Application > Extend Web Application</li><li>Use the Web Application box to select the SP App that needs to have impersonation disabled and search enabled.</li><li>Fill out the rest of the settings to your liking. Remember that the new IIS site you are creating need not be accessible by your users. Also remember to make this site not conflict with any existing sites (which can easily be achieved by using the randomly-generated port number).<br /></li><li>Jot down what's in the URL box under "Load Balanced URL". You'll need it later.</li></ol>The crawler has a path to search, so let's now tell it to search the searchable IIS site and not the user-friendly site.<br /><ol><li>Go to the admin portal for the SharedServices corresponding with the SP app.</li><li>Click on Search Settings > Content Sources and Crawl Schedules</li><li>Click on whatever content source that includes the SP app.</li><li>In the Start Addresses box, replace the line(s) corresponding with the user-friendly IIS site with equivalent line(s) found on the new Searchable IIS site.</li><li>Set the other settings as you like and click OK.<br /></li></ol>Now the search crawler should indeed successfully crawl the SP application, but search itself will yield no results! Why? Because, when you search "in this site", you are searching for things found under the site the user is actually using, whereas the crawler found things under the other site. Same content, different access paths. <br /><br />So we need a way to tell the search engine that everything at the searchable site is <span style="font-style: italic;">really</span> something at the user-friendly site. We do this with Server Name Mappings:<br /><ol><li>Go to the admin portal for the SharedServices corresponding with the SP app.<br /></li><li>Go to Search Settings > Server Name Mappings > New Mapping <br /></li><li> In the "Address in index:" blank, input the address of the searchable IIS site (e.g. http://myServer:12345/)--i.e., the "Load Balanced URL" you wrote down earlier.<br /></li><li>In the "Address in search results" blank, input the address of the user-friendly IIS site (e.g. http://myServer:80/ or https://www.MyBuisnessPortal.org/). This would be the "Load Balanced URL" of the user-friendly site.</li></ol>Please respond with any comments, corrections, or questions you may have.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-83246375511390005402008-08-07T13:34:00.000-07:002008-08-07T13:56:26.058-07:00A code comparison: SendEmail activity vs. SPUtil.SendEmailAlthough shorter is not necessarily faster or easier to understand (much less is shorter always better), the code length of a given way of tackling a problem is nonetheless a useful metric for how valuable it is. So today I shall compare code length of two means of sending email in a SP workflow.<br /><br /><span style="font-weight: bold;">1. Use a SendEmail activity.</span><br /><br />We can actually do this a few different ways:<br /><br /><ol><li>Bind the activity's properties to variables in your workflow and set the values pseudo-statically:<br /><blockquote>private mySendEmailActivity_From = "From Address";<br />private mySendEmailActivity_To = "To Address";<br />private mySendEmailActivity_Subject = "Subject";<br />private mySendEmailActivity_Body = "Body";<br /></blockquote><br /></li><li>(Some say this causes runtime errors!) Just set the properties on the activity itself prior to running it:<br /><blockquote>private void notifyHr_MethodInvoking(object sender, EventArgs e)<br />{<br /> mySendEmailActivity.To = "To Address";<br /> mySendEmailActivity.From = "From Address";<br /> mySendEmailActivity.Subject = "Subject";<br /> mySendEmailActivity.Body = "Body";<br />}<br /></blockquote></li><li>Bind the properties statically AND set them dynamically, which would be about the length of the above two examples added together.<br /></li></ol><br /><span style="font-weight: bold;">2. Code it yourself!</span><br /><br />Many find it more reliable to insert a Code activity and bind it to the following procedure:<br /><blockquote>public void sendRejectionEmail()<br />{<br /> SPUtility.SendEmail(workflowProperties.Web, true, false, workflowProperties.OriginatorEmail, "HR-1 Rejected!", "pwn'd by the approvers! Mwahahaaaa!!!");<br />}</blockquote>That's just one long line of code.<br /><br />So... using the above one-liner should not take any longer to write than using the SendEmail activity.<br /><br /><br /><blockquote></blockquote><blockquote></blockquote>Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-16120940703414449852008-08-06T14:42:00.000-07:002008-08-06T15:05:02.262-07:00More e-mail bluesI have put off wrestling with the particularly pesky (buggy? broken? useless?) SendEmail activity today, and found (to make a long story short):<br /><ol><li>There is no way on earth (it seems) to properly set the correlation token of a SendEmail activity nested within a custom composite activity. Thus, it is incompatible with the most important abstraction mechanism provided by WF, thus it is not useful for development of complex workflows.<br /></li><li>Both the SendEmail activity and the "ability" to notify users of tasks via email (taskProperties.SendEmailNotification == true) are known to throw the workflow-terminating error "The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly" on some servers with properly-configured email settings.</li></ol>I found the aforementioned error message to be thrown by my workflow when:<br /><blockquote>(the workflow was coded to copy data from my initialization form to my task forms) and ( (the tasks were set to send e-mail notifications) or (my SendEmail activity nested within my custom sequential activity was Enabled) ).<br /></blockquote>If the workflow was _not_ coded to copy data my initialization form to my task forms:<br /><ol><li>Upon building the project, I get the following warning:<br />"Activity 'sendRejectionEmail' validation warning: The correlation may be uninitialized."</li><li>Upon starting the SendEmail activity, the workflow crashes with error message:<br />""</li></ol>I tried adding an OnWorkflowActivitated activity to my custom sequential activity, and I set it and the SendEmail activity to the same correlation token. This time,<br /><ol><li>The aforementioned warning goes away! (Maybe I'm onto something!)</li><li>The workflow hangs (never assigns the first task even), and one of the w3wp.exe processes takes up 25% system resources (all it can get in a single thread on a quad-core processor, as is the case with this server).</li></ol>Between this post and my previous one, I think I have made a good case that one should _not_ expect the OOB SendEmail activity to work.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com1tag:blogger.com,1999:blog-5330734641572918892.post-9744984114801874412008-08-06T07:18:00.000-07:002008-08-06T14:55:05.706-07:00The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly.When building a SharePoint workflow that sends email either via the SendEmail activity or the CreateTask activity (with taskProperties.SendEmailNotification = true), many workflows will receive the error message "The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly," even if email works elsewhere (e.g. outside the workflow).<br /><br />I get this message for every task assigned in my workflow, but I know the "offending code" that causes this error. Generally, it is code that copies data from the filled-out initialization form into a task's ExtendedProperties (which will show up in the custom task form). (Also note that the custom Task form has all the same fields as the Initialization form, plus some. I copied and pasted the fields from the Initialization template to the Task template when desiging in InfoPath.)<br /><br />Specifically, in an initialization routine called within onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e), I have several lines that look like the following:<br /><br /><blockquote>taskProperties.ExtendedProperties["MyFieldName<myfieldname>"] = parsedInitData.</myfieldname>MyFieldName<myfieldname><myfieldname>;</myfieldname></myfieldname></blockquote>where:<br /><ul><li>taskProperties is a new SPWorkflowTaskProperties object to which MyCustomActivity.CreateTask_TaskProperties is assigned.</li><li>parsedInitData contains the data placed in the Initialization form that kicks off the workflow.<br /></li><li>MyFieldName is the name of a field in said initialization form template, thus also a form in parsedInitData.</li></ul>SOOO... I find that others have suggested the following workarounds:<br /><ul><li>Most commonly of all, use a custom code activity to send an email. There are 2 variations:<br />-the more conventional way, via your own SMTP server, not even using SP to send the email in any way.<br />-calling the following function:<br /><span><span><span><blockquote><span><span><span><span><span><span>SPUtility.</span></span></span></span></span></span>SendEmail(SPWeb Web, bool fAppendHtmlTag, bool fHtmlEncode, string to, string subject, string htmlbody)</blockquote></span></span></span>(<a href="http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/22f41ab8-4f8b-4e19-8752-faaa1ca19b07/">http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/22f41ab8-4f8b-4e19-8752-faaa1ca19b07/</a>)<br /></li><li>If the problem is only with Tasks that won't send email rather than SendEmail activities per se, then use SendEmail activities instead (<a href="http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/6e848a25-019d-4220-aff6-c535da933e0f/">http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/6e848a25-019d-4220-aff6-c535da933e0f/</a>).</li><li>Use a Sequential workflow rather than a State Machine workflow (<a href="http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/6e848a25-019d-4220-aff6-c535da933e0f/">http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/6e848a25-019d-4220-aff6-c535da933e0f/</a>).</li><li>Bind all the necessary Properties to some variable in VS's Properties window while using Workflow Designer instead of setting them in code (e.g. MyCustomActivity.SendEmailActivity.Subject = "The Subject") (<a href="http://spschris.blogspot.com/2008/03/e-mail-message-cannot-be-sent-make-sure.html">http://spschris.blogspot.com/2008/03/e-mail-message-cannot-be-sent-make-sure.html</a>)</li><li>(My favorite!) Who needs abstraction? Open Pandora's box by moving all SendEmail activities out of your custom composite activities and into your Workflow (at the top level). (<a href="http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/22f41ab8-4f8b-4e19-8752-faaa1ca19b07/">http://forums.msdn.microsoft.com/en-US/sharepointworkflow/thread/22f41ab8-4f8b-4e19-8752-faaa1ca19b07/</a>)</li></ul>What workarounds work for you all, my readers (all zero of you)? I shall investigate what to do in my specific situation today.<br /><blockquote></blockquote>Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com2tag:blogger.com,1999:blog-5330734641572918892.post-74163958932623619842008-07-28T10:14:00.000-07:002008-08-06T07:23:21.161-07:00Different behavior when a breakpoint is hit.Today's SP mystery: I have a workflow that works as expected when run, with or without the debugger attached, <span style="font-style: italic;">unless</span> it hits a (certain?) breakpoint, in which case the UI says:<br /><br /><span id="ctl00_PlaceHolderMain_LabelMessage"></span><blockquote><span id="ctl00_PlaceHolderMain_LabelMessage">The workflow failed to start due to an internal error.</span> </blockquote><br />Why? I dunno!<br /><br />EDIT: Upon further testing, I found the workflow to work only intermittently when not in debug mode. Upon revising my build scripts (most notably setting all dependent projects' Copy Local properties to True (even though I always thought that was default behavior), everything worked right.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-8317076959469621672008-07-25T10:09:00.001-07:002008-08-06T07:30:18.493-07:00This task is currently locked by a running workflow and cannot be edited.Yet another mysterious error I'm still researching. For my complex MOSS workflow with InfoPath forms, I do the following:<br /><ol><li>Remove Workflow from associated list.</li><li>Remove corresponding feature from entire farm (for good measure).<br /></li><li>Clean and rebuild entire workflow solution.</li><li>Deploy workflow.</li><li>Start the workflow on an existing item in associated list.</li><li>Fill out the initiation form (that was built via InfoPath and VSTA).</li><li>Get an error screen saying: "<span id="ctl00_PlaceHolderMain_LabelMessage">The workflow failed to start due to an internal error" (even though I have set every bloomin' Web.config file on the server to NOT show custom errors and TO show a call stack).</span></li><li><span id="ctl00_PlaceHolderMain_LabelMessage">I return to the associated list.</span></li><li><span id="ctl00_PlaceHolderMain_LabelMessage">*le gasp* The item says its workflow is "Completed" despite the error!</span></li><li><span id="ctl00_PlaceHolderMain_LabelMessage">I check on the status of the completed workflow, and see it has created 1 task (after which it was supposed to wait for that task to be updated or completed, infopath form and all, after which it was supposed to assign another task).</span></li><li><span id="ctl00_PlaceHolderMain_LabelMessage">I click on the task, then on "Edit Item", then "OK".</span></li><li><span id="ctl00_PlaceHolderMain_LabelMessage">I repeat step 11, but this time when I click "OK", I get the error message "</span>This task is currently locked by a running workflow and cannot be edited."</li></ol>Yet the Workflow has completed. Hmmm...<br /><br />I know I made an error somewhere (probably failed to correctly include a Form for the tasks or something), but geez, some uncontradictory information would be helpful!<br /><br />Stay tuned for a solution (if I ever find one! :P).<br /><br />EDIT: I think I resolved this by setting TaskListContentTypeId="0x01080100C9C9515DE4E24001905074F980F93160" in my workflow.xml. This is what you use if you do NOT define a content type in SP first (as is the case with this workflow). Evidently, this ID is universally recognized as the code for custom content schemas defined by attached InfoPath forms with URN's corresponding to those found in the MetaData section of Workflow.xml. In other words, all tasks with TaskProperties.TaskType=X will have ExtendedProperties corresponding to the InfoPath form whose URN == TaskX_FormURN.<br /><br />Please respond with any corrections to any misunderstandings of mine. Thanks!Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com1tag:blogger.com,1999:blog-5330734641572918892.post-66216445751868507952008-07-16T09:23:00.000-07:002008-07-16T09:32:43.200-07:00InfoPath Forms w/ Code-behinds in SP WorkflowsTruly an amazing integration of vastly different products is that of InfoPath Forms, WF, and SharePoint (MOSS 2007 specifically). Whereas the tutorials and books I have read semi-sufficiently cover the process of publishing an InfoPath Form with no code-behind (no VS projects involved), they do not give extra steps necessary for Forms with code-behinds. I got my Form to work with the following two additional steps:<br /><ol><li>Add a build script copying the Form's .dll to the Feature folder (i.e. the VS Workflow project folder if you're using VS 2008).</li><li>Add the following to the Feature.xml file:<blockquote><elementfile location = "MyForm.dll"><br /></blockquote></li></ol>SO, I take it that, for all .dll's involved in the WF project, we must either:<br /><ul><li>deploy them to the GAC, or</li><li>add them to the Feature folder <span style="font-style: italic;">and </span>reference them in the Feature.xml file, eh?<br /></li></ul>Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-65148256720035885812008-07-16T09:14:00.000-07:002008-07-16T09:23:32.318-07:00Workflow ActivitiesIn addition to steps that books and tutorials everywhere will tell you, I found I had to take two extra steps to incorporate a custom activity in a custom workflow built in VS 2008:<br /><ol><li>Create a strongly-named / signed VS project for the Activity(s) <span style="font-style: italic;">separately</span> from the Workflow project in which said Activity(s) would be used.</li><li>Deploy the activity project's .dll to the GAC <span style="font-style: italic;">before</span> deploying the Workflow, in my case via the build script: <blockquote>"C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" /i "<output>HR New Hire Activity Library.dll"</blockquote></li></ol>Googling was required to find the above 2 steps. I would normally expect that the default Workflow build scripts would take care of things like that.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-47986494647238395152008-05-29T06:38:00.000-07:002008-05-29T06:46:52.500-07:00Invalid debug settings when trying to deploy a SharePoint workflow project.When trying to deploy a SP Workflow, I got the following error message:<br /><br />"The debug settings are not valid. Restart the SharePoint Workflow Project Setup Wizard to enter the settings again."<br /><br />Thanks to <a href="http://russellmccloy.blogspot.com/2008/04/debug-settings-are-not-valid-restart.html">this blog entry</a>, I found what was wrong, though not why it was wrong. Somehow, the "local site [that I] want to use for debugging" (found when you right-click on the project and go to SharePoint Debug Settings) was reset to http://<my>/Docs, which was incorrect. Fixing it is obvious, but how do I avoid this problem in the future?<br /><br />I was using a SP Sequential Workflow project in VS 2008 w/ an InfoPath form, deploying to a MOSS 2007 server.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0tag:blogger.com,1999:blog-5330734641572918892.post-2657016972676611962008-05-29T06:06:00.000-07:002008-05-29T06:36:40.479-07:00I am a newbie SharePoint developer wanting to document some of the more hard-to-find information that I find concerning SharePoint, hence this here blog.Jasonhttp://www.blogger.com/profile/03187895914443569608noreply@blogger.com0