views:

233

answers:

3

Hi all, i have the following method in a WCF service, that has been deployed to SharePoint using Shail Malik's guide:

[OperationContract]
public string AddItem(string itemTitle, Guid? idOfListToUse)
{
  using (var portal = new SPSite(SPContext.Current.Site.Url, SPContext.Current.Site.SystemAccount.UserToken))
  {
    using (var web = portal.OpenWeb())
    {          
      Guid listId;

      web.AllowUnsafeUpdates = true;

      if (idOfListToUse != null && idOfListToUse.Value != new Guid())
      {
        listId = idOfListToUse.Value;
      }
      else
      {
        try
        {
          listId = new Guid(web.Properties[PropertyBagKeys.TagsList]);
        }
        catch (Exception ex)
        {
          throw new MyException("No List Id for the tag list (default list) has been found!", ex);
        }
      }

      var list = web.Lists[listId];

      string title = "";

      SPSecurity.RunWithElevatedPrivileges(delegate{
        var newItem = list.Items.Add();
        newItem["Title"] = itemTitle;
        newItem.Update();
        title = newItem.Title;
      });

      web.AllowUnsafeUpdates = false;

      return title;
    }
  }
}

When the method gets called from Javascript (using Rick Strahl's excellent ServiceProxy.js) it fails and it does so on newItem.Update() because of ValidateFormDigest().

Here's the kicker though, when I step through the code it works! No exceptions at all!

A: 

I don't think you can access 'list' as it was created outside the elevated code block.

http://blogs.pointbridge.com/Blogs/herzog%5Fdaniel/Pages/Post.aspx?%5FID=8

I'm guessing when you are stepping though the entire process is in admin mode so all are elevated.

MattC
The RunWithElevatedPriviliges was just a tryout, The entire code block is in a using statement that opens the SPSIte with the SystemAccount's UserToken.
Colin
+1  A: 

Ok, found the answer (there's 2 even :-D)

First, the dirty one:

Set FormDigestValidatedProperty in the context:

HttpContext.Current.Items["FormDigestValidated"] = true;

Second, the slightly less dirty version (basically leaving the way open for XSS attacks, but this is an intranet anyway)

The answer

Colin
A: 

Colin, it's a really bad idea to try to access HttpContext (likewise SPContext) inside a WCF service. See here: MSDN: WCF Services and ASP.NET

From the article:

HttpContext: Current is always null when accessed from within a WCF service.

It's likely this is the cause of your problem.

EDIT: I notice that you're trying to use SPContext to get the url of the site collection. I didn't find a good solution to this either so I just send the url of the target site collection as a parameter to the service call. Not the most optimal solution but I couldn't think of a better way. Also, if you need to check authentication/identities, etc use ServiceSecurityContext.Current.

Repo Man
I have set the aspNetCompatibilityEnabled to true, which puts the service in the asp.net pipeline. I don't need an "exact" context anyway, just enough to get a url and the systemaccount's usertoken.With those I open a new SPSite.
Colin