Author Archive for dmgorman

26
Aug
09

#31 Linq Parsing – checking for missing XElement

I am loading an object fed from an XML document that expects a string for each element whether it exists or not. Since some elements are optional this bit of code helps return an empty string instead of getting a null exception. The method loadElement below checks for null and returns string.empty instead.

See http://www.switchonthecode.com/tutorials/introduction-to-linq-simple-xml-parsing for parsing code


private List<SampleObject> readParse( string FilePath)
{

XDocument xmlDoc = XDocument.Load(FilePath);

List< SampleObject > ObjectList  =
(from RANGEVARNAME in xmlDoc.Descendants("PARENTNODE")
select new SampleObject
{

item1     =  loadElement(RANGEVARNAME.Element("item1")),
item2     =  loadElement(RANGEVARNAME.Element("item2")),
. . .
}).ToList<SampleObject>();

lblMessage.Text = "Loading " + FilePath + " (" + ObjectList.Count + ") Records";

return (ObjectList);

}

 private string loadElement(XElement E)
{
  return((E==null)? string.Empty: E.Value);
} 
20
Jul
09

#30 Sharepoint: Accessing a Site Collection\SPWeb within a Workflow and updating a list

Below I am grabbing data off a Workflow with a browser enabled Infopath Form and loading a separate list.


public Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties workflowProperties = new Microsoft.SharePoint.Workflow.SPWorkflowActivationProperties(); 

  private void onWorkflowActivated1_Invoked(object sender, ExternalDataEventArgs e)
        {

              ...
                //Save the identifier for the workflow
                workflowId = workflowProperties.WorkflowId;

                // InitiationData comes from the initialization form
                XmlDocument document = new XmlDocument();
                document.LoadXml(workflowProperties.InitiationData);

                // Get Data Off Of Init Form
                XmlNamespaceManager ns = new XmlNamespaceManager(document.NameTable);
                ns.AddNamespace("my", "http://schemas.microsoft.com/office/infopath/2003/myXSD/2006-12-05T20:04:17");
                managerUsername = document.SelectSingleNode("/my:flowFields/my:managerUsername", ns).InnerText;
                managerFullname = document.SelectSingleNode("/my:flowFields/my:managerFullname", ns).InnerText;
                reviewType = document.SelectSingleNode("/my:flowFields/my:reviewType", ns).InnerText;
                reviewComments = document.SelectSingleNode("/my:flowFields/my:reviewComments", ns).InnerText; 

                using (SPSite siteCollection = workflowProperties.Site)
                {
                    using (SPWeb web = siteCollection.OpenWeb())
                    {
                        SPList EmployeeReviewList = (SPList)web.Lists["EmployeeReview"];                     // Specific List
                        SPListItem EmployeeReviewItem = OptimizedAddItem(EmployeeReviewList);       // Add New Item to List
                        EmployeeReviewItem["Review Name"] = reviewType;                                            // Update elements of new item
                        EmployeeReviewItem.Update();
                    }
                }  

  ... }

       //cf.  http://blog.robgarrett.com/2009/02/25/efficient-way-to-add-a-new-item-to-a-sharepoint-list
        public  SPListItem OptimizedAddItem(SPList list)
        {
            const string EmptyQuery = "0";
            SPQuery q = new SPQuery { Query = EmptyQuery };
            return list.GetItems(q).Add();
        }

Credit due for OptimizedAddItem(): http://blog.robgarrett.com/2009/02/25/efficient-way-to-add-a-new-item-to-a-sharepoint-list/

15
Jul
09

#29 PopUp under Deltek 6.x Smart Client

The issue is that by running a smart client an iframe or window open launches a browser window separate from the smart client which is a Windows client executable & not a browser app. Since that is unavoidable using a modal window with target self tag in the head works best. This method will however still leave the initial help window open in the smart client.

Add the Help Icon ? and replace the Help Text (directly via a control-V paste do not click on ellipse to launch editor) with:

<script>javascript:  window.showModalDialog("http://targetpage.aspx",'_parent', "dialogHeight: 200px;");</script>

In your target page (html or aspx) since this is a modal window this will ‘correct’ any postbacks from launching a new window.

<HTML>
                <HEAD>
                                <base target="_self" />
 ...

Put a button with a OnClick event to close this popup. The window.opener=’X';window.open(”,’_parent’,”);window.close(); will avoid the usual warning.

Credit Due on avoiding the window close warning: http://blogs.x2line.com/al/articles/350.aspx

					function CopyToClipboard()
					{
						document.frmVisible.txtJobNumber.focus();
						document.frmVisible.txtJobNumber.select();
						CopiedTxt = document.selection.createRange();
						CopiedTxt.execCommand("Copy");
						alert('Number has been copied. Use Control-V to paste into new project screen.');
						window.opener='X';window.open('','_parent','');window.close();
					}

cf . http://dmgorman.wordpress.com/2008/01/11/02-simple-popup-help-page/

26
Jun
09

#28 Deltek operator (agent) ID & email via Workflow

If you need to get the agent processing the workflow you can call the UDF GetVisionAuditUsername()

You can then wrap this UDF call in a SP to get something like an Email address from the EM table for email processing to the operator/agent which is something missing from Deltek’s WF options. Sending the person doing the operation (agent) an email has been missing in Deltek WF (you can send their manager an email but not the person doing the work). At least this is what we see in 5.1 and since 6.0 is same/same we probably have the same issue there – though I have not checked there. If anyone sees otherwise please post a comment. Thanks!


** Note: This will require the context provided by Deltek’s WF since the UDF uses ‘context_info’ from master.dbo.sysprocesses **

Create Procedure getAgentEmail()
AS
BEGIN
	Declare @Employee as varchar(20)

	Select @Employee = [dbo].[GetVisionAuditUsername]()

	Select EM.Email
        From EM
        Where EM.Employee = Substring(@Employee,1,3)
            -- substring if needed to get proper key

         -- It would be wise to parm these values in!
         EXEC msdb..sp_send_dbmail
            @profile_name='ProfileName'
           , @recipients= @Email
           , @subject='Test message'
           , @body='This is the body of the test message'

END

SQL 2008 Mail Setup
http://blog.sqlauthority.com/2008/08/23/sql-server-2008-configure-database-mail-send-email-from-sql-database/

03
Jun
09

#27 Simple Ajax WebPart Setup

This post is liberally linked into other very good resources – I only offer it as a help or path through some of the options. The ‘lazy’ web.config reconfigure via Visual Studio framework switch is very effective. I did it manually on a test system and had a lot of control reference problems. I will be trying it again to better understand what I missed though this time with a web.config to run a diff against.

Install Net Framework 3.5 SP1

Web.Config Setup

  1. Backup site web.config
  2. Create a 2.0 web app in VS
  3. Copy in web.config
  4. Change target framework to 3.5 and save web.config over production.
  5. Reference: http://weblogs.asp.net/jan/archive/2008/10/10/enabling-net-3-5-in-sharepoint-2007-sites-the-lazy-way.aspx

Add safe control in <Sharepoint><SafeControls> make sure it is 3.5.0.0 (if 3.5 SP1 installed)

  1. Reference: http://sharepoint.microsoft.com/blogs/mike/Lists/Posts/Post.aspx?ID=3  (see Point 6 )
  2. Reference: http://www.codeproject.com/KB/sharepoint/MossAjaxWebPart.aspx?display=PrintAll&fid=417786&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2156594

Default.Master

  1. Add SPScriptManager to (default) master page via SPD (Sharepoint Designer)  – here is where to place it.

 <form runat=”server”>

<WebPartPages:SPWebPartManager runat=”Server” />

<asp:ScriptManager runat=”server” ID=”ScriptManager1″>

</asp:ScriptManager>

<TABLE class=”ms-main” CELLPADDING=0 CELLSPACING=0 BORDER=0

WIDTH=”100%” HEIGHT=”100%”>

SPD designer gives a IE 6 warning ?? ignore it

Ajax Web Part

  1. Deploy a simple Ajax Web Part
  2. Reference: http://jamestsai.net/Blog/post/How-To-Create-AJAX-enabled-SharePoint-Web-Part-with-UpdatePanel-and-UpdateProgress-in-10-minutes.aspx
02
Jun
09

#26 Remove Offending WebPart causing a sever error

Occasionally I have ‘friends’ that hammer a page and have a hard time getting back to Kansas.   Recently, I (ahem) my friend added a Ajax WP forgetting to add the ScriptManager to the master page which causes a parse error and you cannot get back into the page via SPD or other means (easily).   You often get a SPD view error jamming you up :

soap:ServerServer was unable to process request. —> A Web Part or Web Form Control on this Web Part Page cannot be displayed or imported because it is not registered as safe on this site. You may not be able to open this page in an HTML editor that is compatible with Microsoft Windows SharePoint Services, such as Microsoft Office SharePoint Designer. To fix this page, contact the site administrator to have the Web Part or Web Form Control configured as safe. You can also remove the Web Part or Web Form Control from the page by using the Web Parts Maintenance Page. If you have the necessary permissions, you can use this page to disable Web Parts temporarily or remove personal settings. For more information, contact your site administrator.

There is a ‘trick’ to view web parts on a page and delete the offender. Go to the Brown Screen of Death page and add ?contents=1 at the end of the URL.  The browser will display (depending on permissions) a maintence view and the Web Parts that are the page – where you can delete the offender.

Credit due: http://www.blogcoward.com/archive/2009/03/29/Sharepoint-Designer-2007-A-Web-Part-or-Web-Form-Control.aspx

29
May
09

#25 Birthdays & Service Anniversaries

Birthdays & Years of Service

Birthdays & Years of Service

Variation on a theme – here we display weekly birthdays & service anniversaries.

Stored Procedure:


Procedure SP_Weekly
as
Select EM.Employee as EmpNum
, EmployeePhoto
, isNull(EM.PreferredName,EM.FirstName) + ' ' + RTRIM( EM.LastName) as EmployeeName
, RTRIM(datepart(month,custEmp_BirthDate)) + '/' +  RTRIM(datepart(day,custEmp_BirthDate)) as DateField
, 'Birthday'  as Notes
From EmployeeCustomTabFields ECTF
Join EM on (EM.Employee = ECTF.Employee)
Where
datepart(week,custEmp_BirthDate) = datepart(week,getdate())
And Status = 'A'
Union All
Select EM.Employee as EmpNum
, EmployeePhoto
, isNull(EM.PreferredName,EM.FirstName) + ' ' + RTRIM( EM.LastName) as EmployeeName
, RTRIM(datepart(month,HireDate)) + '/' +  RTRIM(datepart(day,HireDate))
  + '/' +  RTRIM(datepart(year,HireDate)) as DateField
, Cast(DateDiff(year, HireDate, getdate()) as varchar(12)) + RTRIM(' Years of Service' )  as Notes
From EmployeeCustomTabFields ECTF
Join EM on (EM.Employee = ECTF.Employee)
Where
datepart(week,HireDate) = datepart(week,getdate())
And Status = 'A'
Order By 4
28
May
09

#24 Small Employee Directory SP Web Part

Employee Directory for Sharepoint Column

Employee Directory for Sharepoint Column

This web part exposes props for an advance search URL, results table width and max record count. The results are displayed via bind to an ASP.Net Repeater.

properties exposed in Sharepoint

properties exposed in Sharepoint

Credit Due for dynamic template code

BWEmpDirSmall.cs

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
//add
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;
using System.Data.Common;
using System.Web.Configuration;
using System.Data.SqlTypes;
using System.Xml.Serialization;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using System.IO;

namespace BWEmpDirSmall
{
    [Guid("60c0ce25-603a-4c24-8d99-8b6046f013fe")]
    public class BWEmployeeSearch2 : Microsoft.SharePoint.WebPartPages.WebPart
    {
        private bool _error = false;

        private Label lblMessage;
        private TextBox txtSearch;
        private Button btnSearch;
        private Button btnClear;
        private Repeater rptList;
        private HyperLink hlAdvSearch;

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("My Property Group")]
        [WebDisplayName("Advance Search Page")]
        [WebDescription("URL to Advance Search")]
        public string AdvSearchURL { get; set; }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("My Property Group")]
        [WebDisplayName("Table Width")]
        [WebDescription("Filter &amp; Results Table Width")]
        public string TableWidth { get; set; }

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [System.ComponentModel.Category("My Property Group")]
        [WebDisplayName("Max Count")]
        [WebDescription("Maximum Rows Returned")]
        public string MaxCount { get; set; }
        public BWEmployeeSearch2()
        {
            this.ExportMode = WebPartExportMode.All;
            this.AdvSearchURL = @"<a href='http://portal'>******</a>";
            this.TableWidth = "220px";
            this.MaxCount = "25";
        }

        /// <summary>
        /// Sets Display
        /// </summary>
        /// <param name="writer"></param>
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write("<table width='" + TableWidth + "' border='0' >");

            spanRow(writer, "left", "2");
            //writer.Write("<b>Search: </b>");

            txtSearch.RenderControl(writer);
            writer.Write("&nbsp;");
            btnSearch.RenderControl(writer);
            writer.Write("&nbsp;");
            btnClear.RenderControl(writer);
            rowEnd(writer);

            spanRow(writer, "left", "2");
            hlAdvSearch.RenderControl(writer);
            rowEnd(writer);

            spanRow(writer, "left", "2");
            lblMessage.RenderControl(writer);
            rowEnd(writer);

            spanRow(writer, "left", "2");
            rptList.RenderControl(writer);
            rowEnd(writer);

            writer.Write("</table>");
        }

        protected void rowStart(HtmlTextWriter writer, string sAlign) { writer.Write("<tr><td align=" + sAlign + ">"); }
        protected void cellEnd(HtmlTextWriter writer) { writer.Write("</td>"); }
        protected void cellEndStart(HtmlTextWriter writer, string sAlign) { writer.Write("</td><td align=" + sAlign + ">"); }
        protected void rowEnd(HtmlTextWriter writer) { writer.Write("</td></tr>"); }
        protected void spanRow(HtmlTextWriter writer, string sAlign, string colspan)
        {
            writer.Write("<tr><td align=" + sAlign + " colspan=" + colspan + " >");
        }

        /// <summary>
        /// Create all your controls here for rendering.
        /// Try to avoid using the RenderWebPart() method.
        /// </summary>
        protected override void CreateChildControls()
        {
            if (!_error)
            {
                try
                {

                    base.CreateChildControls();

                     lblMessage = new Label();
                    btnSearch = new Button();
                    btnClear = new Button();
                    txtSearch = new TextBox();
                    hlAdvSearch = new HyperLink();

                    this.lblMessage.Width = new Unit("200px");

                    this.btnSearch.Text = "Search";
                    this.btnSearch.Click += new EventHandler(btnSubmit_Click);
                    this.btnClear.Text = "Clear";
                    this.btnClear.Click += new EventHandler(btnClear_Click);

                    this.rptList = new Repeater();
                    this.rptList.ItemTemplate = new MyTemplate(MaxCount);

                    this.hlAdvSearch.Text = "Advance Search";
                    this.hlAdvSearch.NavigateUrl = AdvSearchURL;

                    this.Controls.Add(lblMessage);
                    this.Controls.Add(txtSearch);
                    this.Controls.Add(rptList);
                    this.Controls.Add(btnSearch);
                    this.Controls.Add(btnClear);
                    this.Controls.Add(hlAdvSearch);

                    this.lblMessage.Width = new Unit("180px");
                    this.btnSearch.Width = new Unit("60px");
                    this.btnClear.Width = new Unit("60px");
                    this.txtSearch.Width = new Unit("150px");

                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        }

        /// <summary>
        /// Ensures that the CreateChildControls() is called before events.
        /// Use CreateChildControls() to create your controls.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            if (!_error)
            {
                try
                {
                    base.OnLoad(e);
                    this.EnsureChildControls();

                    // Your code here...
                }
                catch (Exception ex)
                {
                    HandleException(ex);
                }
            }
        }

        /// <summary>
        /// Clear all child controls and add an error message for display.
        /// </summary>
        /// <param name="ex"></param>
        private void HandleException(Exception ex)
        {
            this._error = true;
            this.Controls.Clear();
            this.Controls.Add(new LiteralControl(ex.Message));
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {

            this.rptList.ItemTemplate = new MyTemplate(MaxCount);

            if (Utilities.hasData(txtSearch))
                bindRepeater();
            else
            {
                lblMessage.Text = "No Search Criteria Entered";
                //this.rptList.DataSource = new string[] { }; //clear
                //this.rptList.DataBind();
            }

        }
        protected void btnClear_Click(object sender, EventArgs e)
        {
            txtSearch.Text = string.Empty;
            this.rptList.DataSource = new string[] { }; //clear
            this.rptList.DataBind();
            lblMessage.Text = "";
        }
        private void bindRepeater()
        {
            DataSet ds = Employee.searchEmployees(txtSearch.Text.Trim());
            this.rptList.DataSource = ds;
            this.rptList.DataBind();
            int iRecCount = 0;
            Int32.TryParse(ds.Tables[0].Rows.Count.ToString(),out iRecCount);
            if (iRecCount < (Int32.Parse(MaxCount)))
                this.lblMessage.Text = iRecCount.ToString() + " record(s) found";
            else
                this.lblMessage.Text = iRecCount.ToString() + " Recs Exceeded " + MaxCount + " Max";
        }

    }
}

MyTemplate.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace BWEmpDirSmall
{
    public class MyTemplate : ITemplate
    {

            static int itemcount = 0;
            static int MAXCOUNT = 25;
            ListItemType templateType;

            public MyTemplate()
            {
                templateType = ListItemType.Item;
                itemcount = 0;
            }

            public MyTemplate(string s)
            {
                templateType = ListItemType.Item;
                MAXCOUNT = 25;
                Int32.TryParse(s, out MAXCOUNT);
                itemcount = 0;
            }

            public MyTemplate(ListItemType type)
            {
                templateType = type;
                itemcount = 0;
            }

            public void InstantiateIn(System.Web.UI.Control container)
            {
                Literal lc = new Literal();
                //switch (templateType)
                //{
                //    case ListItemType.Header:
                //        lc.Text = "<TABLE border=1><TR><TH>Items</TH></TR>";
                //        break;
                //    case ListItemType.Item:
                //        //lc.Text = "<TR><TD>Item number: " + itemcount.ToString() +
                //        //   "</TD></TR>";
                //          lc.Text = DataBinder.Eval(Container.DataItem, "FirstName");
                //        break;
                //    case ListItemType.AlternatingItem:
                //        lc.Text = "<TR><TD bgcolor=lightblue>Item number: " +
                //           itemcount.ToString() + "</TD></TR>";
                //        break;
                //    case ListItemType.Footer:
                //        lc.Text = "</TABLE>";
                //        break;
                //}
                if (itemcount <= MAXCOUNT)
                {
                    lc.DataBinding += new EventHandler(TemplateControl_DataBinding);
                    container.Controls.Add(lc);
                }
                itemcount++;

            }

            private void TemplateControl_DataBinding(object sender, System.EventArgs e)
            {
                Literal lc;
                lc = (Literal)sender;
                RepeaterItem container = (RepeaterItem)lc.NamingContainer;
                lc.Text += "&amp;raquo; <font color='#99000'><b> ";
                lc.Text += DataBinder.Eval(container.DataItem, "FirstName");
                lc.Text += " &nbsp;" + DataBinder.Eval(container.DataItem, "LastName");
                lc.Text += "</b></font> ";
                if (Utilities.hasData(DataBinder.Eval(container.DataItem, "WorkPhoneExt").ToString()))
                    lc.Text += "<b> x/" + DataBinder.Eval(container.DataItem, "WorkPhoneExt") + "</b>";
                lc.Text += "<br />";
                if (Utilities.hasData(DataBinder.Eval(container.DataItem, "WorkPhone").ToString()))
                    lc.Text += "&nbsp;<i>" + DataBinder.Eval(container.DataItem, "WorkPhone") + "</i>&nbsp;";
                if (Utilities.hasData(DataBinder.Eval(container.DataItem, "MobilePhone").ToString()))
                    lc.Text += "<i> Cell: " + DataBinder.Eval(container.DataItem, "MobilePhone") + "</i> ";
                lc.Text += "<br /> ";
            }
    }

}

Employee cs searchEmployees method:

static public DataSet searchEmployees(string sTarget)
    {

        SqlCommand cmd = null;
        SqlDataAdapter da = null;
        DataSet ds = new DataSet("Employees");
        using (SqlConnection conn = Utilities.getConnR())
        {

            try
            {
                cmd = new SqlCommand("searchEmployees", conn);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add(new SqlParameter("@Target", SqlDbType.Text));
                cmd.Parameters["@Target"].Value = sTarget.Trim();

                conn.Open();
                da = new SqlDataAdapter(cmd);
                da.Fill(ds);

            }
            catch (Exception err)
            {
                throw new ApplicationException(err.Message.ToString());

                //err.Message.ToString();
            }
            finally
            {
                if (cmd != null) { cmd.Dispose(); }
                if (da != null) { da.Dispose(); }
            }
        }
        return ds;

    }

Stored Procedure:

Procedure [dbo].[searchEmployees]
(
  @Target  nvarchar(50)
)
as
  Select
   EM.Employee as EmpNum
 , RTRIM(EM.Employee) + '-' +  SUBSTRING(EM.FirstName,1,1)
  +  RTRIM(Case When(DATALENGTH(EM.MiddleName) = 0) Then '' Else  SUBSTRING(EM.MiddleName,1,1) End )
     +  SUBSTRING(EM.LastName,1,1)  as Employee
 , isNull(EM.PreferredName,EM.FirstName)    as FirstName
 , (RTRIM(EM.LastName) + ' ' + isNull(Suffix,''))  as LastName
 , EM.MiddleName
 , EM.Org         as PrimaryDept
 , EM.Region
 , EM.WorkPhone
 , EM.WorkPhoneExt
 , EM.MobilePhone
 , ECTF.Cust5ULPhysical      as Office
 , ECTF.custSecondaryDepartment     as SecondaryDept
  From
    EM
  Join EmployeeCustomTabFields ECTF on ( ECTF.Employee = EM.Employee )
  Where
 EM.Status = 'A'
 And (  EM.FirstName  like  Case When (@Target is null) Then '%' Else RTRIM(@Target) + '%' End
     OR EM.PreferredName   like  Case When (@Target is null) Then '%' Else RTRIM(@Target) + '%' End
     OR EM.LastName   like  Case When (@Target is null) Then '%' Else RTRIM(@Target) + '%' End
   OR    SUBSTRING(EM.FirstName,1,1)  +  RTRIM(Case When(DATALENGTH(EM.MiddleName) = 0) Then '' Else  SUBSTRING(EM.MiddleName,1,1) End )  +  SUBSTRING(EM.LastName,1,1)  like Case When (@Target is null) Then '%' Else  @Target  End
     OR EM.WorkPhone like '%' + isNull(@Target,'%') + '%'
   OR EM.WorkPhoneExt like '%' + isNull(@Target,'%') + '%'
   OR EM.MobilePhone like '%' + isNull(@Target,'%') + '%'
   OR  ECTF.Cust5ULPhysical = isNull(@Target, ECTF.Cust5ULPhysical)
   OR  EM.Employee like  isNull(@Target,'%') + '%'   )
12
May
09

#23 Installing Business Data Catalog Definition Editor – error 2869

When installing the Business Data Catalog Definition Editor which allows (makes it easy for) you to connect your data sources to the Sharepoint Business Data Catalog you can get this odd error. I was loading in Windows Server 2003 & all the posts I saw were for issues with Vista.  Hope this helps those non-Vista users suffering this issue.

My Log entry:

Event Type:    Error Event Source:    MsiInstaller Event Category:    None Event ID:    10005 Date:        Time:          PM User:        CSISERVER Description: Product: Microsoft ®  Application Definition Designer — The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2869.

For those that install packages a lot this may be obvious – use the setup.exe directly instead of the msi package. It will install SQL 2005 Express with the app (there are some unhappy posts on that around) but the Definition Editor installs.

If looking for the SDK here are the links:

http://blogs.msdn.com/sharepoint/archive/2007/08/22/announcing-the-microsoft-business-data-catalog-definition-editor-for-microsoft-office-sharepoint-server-2007.aspx
http://www.microsoft.com/downloads/details.aspx?familyid=6d94e307-67d9-41ac-b2d6-0074d6286fa9&displaylang=en



27
Feb
09

#22 Some Sharepoint links regarding CAML, F# & LINQ

Navigating the vast object model in SP/MOSS can be daunting -  Here are some references regarding some good unifying work:

LINQ to CAML project

Linq SPListCollection

John Lao’s Exploring SP using F# Excellent blog covering F# and SP

Free F# eBook Free is free though you have to navigate & signup for access to get the pdf

Creating a test VPC for Sharepoint/MOSS