Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

Following my previous question The folowing code when executed locally as a console app is working fine, But when I include the same code in a WCF service, I am getting Access is denied exception.

using (SPSite newspSite = SPContext.Current.Site)
{
     foreach (SPService service in newspSite.WebApplication.Farm.Services)
     {

             foreach (SPJobDefinition jobDefinition in service.JobDefinitions)
             {

                  if (jobDefinition.Name == "Word Automation Services")
                  {
                         jobDefinition.RunNow();
                         break;
                  }

             }
      }
}

This code is giving problems as it is not possible to run Microsoft.SharePoint.Administration methods remotely. The workarounds for this as mentioned here is only working for SPWebService and is not available for WordService.

Solutions Tried:

a)Tried wrapping the code inside

SPSecurity.RunWithElevatedPrivileges(delegate{ [code] })

But getting the same error.

Screenshot

Manged to debug the service,

enter image description here

Are there any alternatives or workarounds???

share|improve this question
    
A few questions: is this a claims auth site? does the user have access to the site the service running on? does the service try to use or read the user's identity from SPContext? is the "client" app SharePoint, console, or other? Are you using dynamic configuration? (see MSDN msdn.microsoft.com/en-us/library/ff521581(office.14).aspx) –  DrivenDevelopment May 3 '12 at 15:11
    
Its using windows login for authenticating, I am not using spcontext anywhere in the code,Its a web service created using CSKDev wcf service visualstudio template. I am not using any config files. –  Flowerking May 3 '12 at 15:38
1  
When you wrapped in RWEP did you change SPSite newspSite = SPContext.Current.Site into SPSite newspSite = new SPSite(SPContext.Current.Site.Id)? By the way you should NEVER write using (SPSite newspSite = SPContext.Current.Site) as this will dispose a SPSite you're not in control of. –  Per Jakobsen May 4 '12 at 11:12
    
Ok. I changed it now and tried redeploying, but it is still trowing the same "Access denied" exception. And thanks for the tip on using statement. I am changing my other code accordingly. –  Flowerking May 4 '12 at 11:58
    
I don't believe that your code works in a console app, since SPContext.Current relies on HttpContext.Current and this is not available in a console app. –  Matthias May 4 '12 at 12:13
show 8 more comments

8 Answers

I had the same issue and got it to work in 2 ways. You have to make the app pool account running the WCF service either an Administrator on the SharePoint Server or make it a Farm Administrator. You also have to give this account rights on the Content Database as well as the SharePoint Config Database. For some reason I am finding out that I also have to give it permissions on the SharePoint_Admin_guid Database.

Anyone know of a way to get this to work with lesser permissions?

Thanks, Sabin

share|improve this answer
    
It is indeed a permission issue, but is it possible to deploy the WCF service without impersonation enabled? I am currently using wcf factory attributes [BasicHttpBindingServiceMetadataExchangeEndpointAttribute] so the only way for me is to make the remote account using the service a farm administrator. It is working for now, but I doubt if it will work when deployed. –  Flowerking Jun 6 '12 at 16:00
add comment

I've hit many similar issues working with custom WCF services hosted inside of SharePoint. Troubles seems to multiply when you add in claims auth. I've often reverted to using asmx services. There are known issues with the dynamic configuration of WCF SOAP services inside of SharePoint (noted here). If appropriate you may want to try configuring it as a WCF REST service instead. There is an blog post here where someone hit an issue with similar symptoms and what they did to resolve it.

share|improve this answer
    
+1 Thank you for answering, the links are informative. However, the problem is within my code, please check updated question. –  Flowerking May 4 '12 at 10:41
add comment

There are a few workarounds that I can think of.

Option 1) Don't use a WCF service, Use client OM to write a simple "flag" item to a list. Associate a workflow to the flag list which starts when new items are added. The workflow could start the timer job.

Option 2) Code an ItemAdded event hander and do the conversion with the ConversionJob class. Example

share|improve this answer
    
Yes, That is what I thought of doing in the first place, but the requirement is to use Sharepoint as a server to convert docx to pdf or other formats, enabling a wcf service that do the conversion and return the file as a stream. So Is my approach is totally wrong then? This requirement is only part of the whole solution, as the word is also generated dynamically. –  Flowerking May 4 '12 at 16:02
    
I see. I didn't realize you had to send the file back. Sounds like you need a message queue (or similar mechanism) so that the client can receive notification (or check to see) when the conversion is complete. I think a syncronous call is going to give you nightmares. –  DrivenDevelopment May 4 '12 at 17:00
    
Yes, I have to check asynchronously till the conversion is complete. –  Flowerking May 4 '12 at 17:04
add comment

I assume your WCF service is hosted SharePoint. Did you used Network Credentials for your Service? Also make sure you are not domains when calling the WCF service.

Please tell me if i'm wrong, but it seems you actually try to force a Word Automation conversion job to run, right? Shouldn't you rather than use something like this (to trigger a specific Conversion Job):

string siteUrl = "http://sp.local";
    string wordAutomationServiceName = "Word Automation Services";
    using (SPSite spSite = new SPSite(siteUrl))
    {
        ConversionJob job = new ConversionJob(wordAutomationServiceName);
        job.UserToken = spSite.UserToken;
        job.Settings.UpdateFields = true;
        job.Settings.OutputFormat = SaveFormat.PDF;
        job.AddFile(siteUrl + "/Shared%20Documents/Test.docx", siteUrl + "/Shared%20Documents/Test.pdf");
        job.Start();
    }
share|improve this answer
    
Yes, its hosted on sharepoint, please check my other question for cofig. and other details. I am using imperosonation with ntlm and its working fine for other operations for the same service. But for the operation containg the above code block giving Access denied error. –  Flowerking May 4 '12 at 14:28
    
see my edit above! –  C. Marius - MVP May 4 '12 at 16:28
    
This is exactly what my code is, but it is adding a conversion job to the job queue. And the conversion is starting when the conversion timer job is scheduled to run. Instead, I am trying to force it using my above code after starting the job as in your code - which is working in a console app but giving problems when called remotely :( –  Flowerking May 4 '12 at 16:57
add comment

First a question, did you create the WCF service using CKSDEV, which creates a SharePoint WCF Service Factory based WCF (cleaner, full SharePoint support, no need for a config file), or a "regular" WCF service deployed to the ISAPI folder?

Also, I do see a few problems:

First, To consume a WCF service running in SP, you always need to set the impersonation level in the consuming code:

var client = new YourServiceClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

Second, elevation only works if you actually create a new context inside it,

SPSecurity.RunWithElevatedPrivileges(delegate{
using (SPSite newspSite = SPContext.Current.Site)    
  {
    // your elevated actions (not actually elevated
  }
}); // the current context is disposed!!

does not create an alevated site object, even worse, it disposes the actual current context! Use the following:

SPSecurity.RunWithElevatedPrivileges(delegate{
  using (SPSite newspSite = new SPSite(SPContext.Current.Site.Url))    
  {
    // your elevated actions
  }
});

Last: Anything running at the farm level being called from a webapp will not work, seeing as even under elevated prviliges the code will run as the web app's apppool, which is not a farm admin (I hope :-D).

Call the service under the Central Admin, which makes it run under that site's app pool (the farm account). This does mean the user running the code needs farm level access, so probably not going to work.

In the past i have circumvented this by assigning an account to a web app's root site collection's secondary site admin. This is a service account (so in AD does not have any logon permissions: logon locally, logon as batch / service etc.) This user should be made a member of the farm admin group. Then use the following code to get that user and then run code as that user:

SPSecurity.RunWithElevatedPrivileges(delegate{
  using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.Url))    
  {
    using (SPSite newspSite = new SPSite(elevatedSite.Url, elevatedSite.SecondaryContact.UserToken))    
    {
      // your elevated actions, running as the secondary admin
    }
  }
});

P.S. The doc conversion service runs asynchronously, so after firing the job, you don't know when it actually executes, so you can't for instance download the resulting document immediately after.

share|improve this answer
    
+1 Thank you Colin for your response. as you can see in the config section <behavior name="NewBehavior0"> i configured impersonation correctly,and I am also ok with your second suggestion. I have to check your last suggestion to see if it works. –  Flowerking May 4 '12 at 17:01
    
And yes, I am using CSKDev template to create the service,and all the config. section is gud as I can use other operations on the service. But only operation with the above code is giving access denied exception. –  Flowerking May 4 '12 at 17:08
    
Tried everything as suggested, still getting same exception strangely. I thought your last approach will get rid of this for me, but to my surprise nothing is working in my way .. –  Flowerking May 8 '12 at 11:06
add comment

Based on some of the other comments, what if you create an additional web service that just starts the timer job on demand? Reference and call this new service (as if it were hosted in the central admin web app) from your existing WCF service. The code that runs inside the new service can run as elevated if need be. I think that should solve the access denied issue.

share|improve this answer
1  
Additionally you can get a Farm reference using SPFarm.Local, you don't have to climb up the object chain from the current site. i.e. SPFarm.Local.Services –  DrivenDevelopment May 4 '12 at 17:41
    
Or May be if I create the new service as you suggested as an .asmx service, then it will most likely end this issue, i think. I will give it a try and will update here accordingly.. Thanks a lot for the help! –  Flowerking May 4 '12 at 17:43
    
ASMX or WCF does not matter, it is the admin code you are trying to run that needs farm admin priviliges (just check the methods you are calling using ILSpy to see the security check in the actual SharePoint code) –  Colin May 4 '12 at 17:47
add comment

I've had a similar issue trying to connect to the user profile web service. I could connect to the web service but would get an access denied error every time I invoked it.

In the end it, it turned out the alternate access mappings were not configured correctly for the url I was trying to access the site with. I would double check the alternate access mappings for the url you are trying to connect with.

Sorry if this doesn't help.

share|improve this answer
add comment

I am facing a similar issue but the difference is that i have the conversion job code in a web part. It is the action initiated by the user.

I have tried giving the app pool account permission on the word automation services in central admin. I have granted db-owner rights to the sharepoint config database as well. (A quick q here : which rights am i supposed to give?)

Please let me know what is wrong as i have been stuck with it for a long long time now.

Code : string wordAutomationServiceName = "Word Automation Services";

                    ConversionJob job = new ConversionJob(wordAutomationServiceName);
                    job.UserToken = iSPSite.SystemAccount.UserToken;
                    job.Settings.UpdateFields = true;
                    job.Settings.OutputFormat = SaveFormat.Automatic;
                    job.AddFile(web.Url + "/" + Constants.collatedArticlesLib + "/" + lblColDocName.Text,
                        FileToSave);
                    job.Start();

                    foreach (var service in iSPSite.WebApplication.Farm.Services)
                    {
                        if (service.TypeName == "Word Automation Services")
                        {
                            foreach (var jobDefinition in service.JobDefinitions)
                            {
                                if (jobDefinition.Name == "Word Automation Services")
                                {
                                    **jobDefinition.RunNow();**
                                    break;
                                }
                            }
                        }
                    }

                    while (true)
                    {
                        Thread.Sleep(5000);
                        ConversionJobStatus status = new ConversionJobStatus("Word Automation Services", job.JobId, null);
                        if (status.Count == status.Succeeded + status.Failed)
                        {
                            break;
                        }
                    }
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.