SPContext.Current null при доступе к Sharepoint WCF с использованием AJAX - PullRequest
3 голосов
/ 14 декабря 2011

Я хочу настроить WCF, который может вызываться AJAX из JavaScript, загруженного из пользовательской веб-части на нашем сайте Sharepoint Foundation 2010.Чтобы упростить обработку на стороне Javascript, я хочу представить службу Restful, которая возвращает Json вызывающей стороне.

Проблема заключается в том, что когда я вызываю сервер с вызовом AJAX, SPContext.Current равен null.

Я использую MultipleBaseAddressWebServiceHostFactory в файле svc для создания веб-сервиса

<%@ Assembly Name="$SharePoint.Project.AssemblyFullName$"%>  
<%@ServiceHost Language="C#" Debug="true"
Service="Driftportalen.LvService.SuggestService"
Factory="Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHostFactory, Microsoft.SharePoint.Client.ServerRuntime, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
     %>

Контракт для веб-сервиса:

[ServiceContract(Namespace = "", ProtectionLevel= ProtectionLevel.None)]  
public interface ISuggestServiceTest
{
    [WebGet(UriTemplate = "/SuggestAddress/{streetprefix}/", ResponseFormat = WebMessageFormat.Json)]
    [OperationContract]
    Dictionary<string, GenericAddress> SuggestAddress(string streetprefix);
}

Реализация веб-сервиса в основном следующая.

[Guid("BA6733B3-F98D-4AD8-837D-7673F8BC527F")]
[BasicHttpBindingServiceMetadataExchangeEndpoint]
[ServiceBehavior(IncludeExceptionDetailInFaults = true, AddressFilterMode = AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode =  AspNetCompatibilityRequirementsMode.Required)]
public class SuggestService : ISuggestServiceTest
{
    private SPWeb currentWeb;

    public SPWeb CurrentWeb
    {
        get
        {
            if (currentWeb == null)
            {
                var siteUrl = SPContext.Current.Web.Url;
                SPSecurity.RunWithElevatedPrivileges(delegate
                {
                    using (var site = new SPSite(siteUrl))
                    using (var web = site.OpenWeb())
                    {
                        currentWeb = web;
                    }
                });
            }
            return currentWeb;
        }
    }


    public Dictionary<string, GenericAddress> SuggestAddress(string streetprefix)
    {
        LvService lvService = new LvService(CurrentWeb);

        Dictionary<string, GenericAddress> suggestions = new Dictionary<string, GenericAddress>();

        //SNIP
        //Code that uses lvService to populate suggestions

        return suggestions;
    }
}

Я подтвердил, что если я вызываю веб-сервис из веб-браузера, все работает, как ожидалось, и что я получаю правильные данные.

Я использую следующий вызов Ajax

 $.ajax({
   url: addressUrl + "/"+request.term,
   dataType: 'json',
   success: function (data) {
      responseCallback(data);
     $(this).removeClass("fetching");
   }
});

Использование Firebug Я проверил, что из javascript вызывается правильный URL, и на стороне сервера я убедился, что правильный код действительно достигнут, но SPContext.Current равен нулю.

SharepointСервер использует Windows и претензии для входа в систему.Это означает, что фактический WCF будет выполняться с использованием другой учетной записи, отличной от решения Sharepoint, но поскольку я развертываю в папке ниже vti_bin, Sharepoint должен предоставить его контекст для WCF.Мне кажется, что вызов AJAX не будет запускать Sharepoint для предоставления своего контекста, в некотором смысле он анонимный.

Сначала я предположил, что виноват сам веб-сервис, так как он случайно произойдет сбой при вызове изБраузер, но я думаю, что я решил эту проблему, установив обновление до Sharepoint Foundation 2010.

Как я могу сделать AJAX-вызов из javascript / веб-службы, которая принимает AJAX-вызовы из Javascript, которые позволяют веб-сервисуполучить доступ к контексту пользователя, который выполнил вход на сайт Sharepoint?

Ответы [ 2 ]

5 голосов
/ 20 февраля 2012

Я разобрался с решением этой проблемы, поэтому хочу поделиться своими выводами на случай, если кто-нибудь еще столкнется с такой проблемой.

Основная проблема вызвана тем фактом, что фабрики Microsoft Microsofts не могут добавить подходящие привязки доступа для вызовов ajax.Это означает, что волшебство аутентификации папки vti_bin не произойдет.Вы получаете работающий svc, но нет контекста Sharepoint, когда вы обращаетесь к нему с помощью вызовов ajax из вашего javascript, даже если обычный доступ работает нормально.

Вы можете решить эту проблему, расширив Factory, чтобы заменить привязки на правильные.

 <%@ Assembly Name="$SharePoint.Project.AssemblyFullName$"%>  
 <%@ServiceHost Language="C#" Debug="true"
 Service="Driftportalen.LvService.SuggestService, $SharePoint.Project.AssemblyFullName$"
Factory="Driftportalen.LvService.AjaxCompatibleRestServiceHostFactory,Driftportalen.LvService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab8de4d18e388c1f"
         %>

Реализация новой фабрики выглядит следующим образом:

public class AjaxCompatibleRestServiceHostFactory : Microsoft.SharePoint.Client.Services.MultipleBaseAddressBasicHttpBindingServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new AjaxCompatibleRestServiceHost(serviceType, baseAddresses);
    }
}

И, наконец, код активации для замены привязок

public class AjaxCompatibleRestServiceHost : Microsoft.SharePoint.Client.Services.MultipleBaseAddressWebServiceHost
{

    public AjaxCompatibleRestServiceHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
    }

    protected override void OnOpening()
    {
        base.OnOpening();

        foreach (ServiceEndpoint endpoint in base.Description.Endpoints)
        {
            if (((endpoint.Binding != null) &&    (endpoint.Binding.CreateBindingElements().Find<WebMessageEncodingBindingElement>() != null)) && (endpoint.Behaviors.Find<WebScriptEnablingBehavior>() == null))
            {
                // try remove any previous behaviours
                while (endpoint.Behaviors.Count > 0)
                {
                    endpoint.Behaviors.RemoveAt(0);
                }
                endpoint.Behaviors.Add(new WebHttpBehavior());
            }

        }


        ServiceDebugBehavior debug = this.Description.Behaviors.Find<ServiceDebugBehavior>();
        // if not found - add behavior with setting turned on 
        if (debug == null)
        {
            this.Description.Behaviors.Add(
                new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
        }
        else
        {
            // make sure setting is turned ON    
            if (!debug.IncludeExceptionDetailInFaults)
            {
                debug.IncludeExceptionDetailInFaults = true;
            }
        }

        ServiceMetadataBehavior metadata =this.Description.Behaviors.Find<ServiceMetadataBehavior>();
        // if not found - add behavior with setting turned on 
        if (metadata == null)
        {
            this.Description.Behaviors.Add(
                new ServiceMetadataBehavior() { HttpGetEnabled = true });
        }
        else
        { 
            // make sure setting is turned ON    
            if (!metadata.HttpGetEnabled)
            {
                metadata.HttpGetEnabled = true;
            }
        }

    }
}

Возможно, вы захотите использоватьWebScriptEnablingBehavior вместо WebHttpBehavior, если вы хотите, чтобы результат был перенесен, когда вы его вернете.

Есть еще несколько вещей, которые следует учитывать.В сети есть некоторые признаки того, что отсутствие SP1 может также привести к отсутствию контекста Sharepoint, поэтому убедитесь, что у вас установлены последние пакеты обновлений, если у вас возникнут проблемы.

Наконец, если вы создаете службу REST, может возникнуть соблазн использовать UriTemplate для получения желаемой структуры URL.К сожалению, на момент написания этой статьи UriTemplate не поддерживалась Microsoft в этом сценарии, поэтому исследуйте эту проблему, прежде чем основывать свой проект на существовании UriTemplate.

4 голосов
/ 25 февраля 2014

Я столкнулся с той же проблемой при использовании SharePoint 2013. У меня не было возможности опробовать ваше решение, потому что я читал о другом, который в основном получает текущий сайт и веб-идентификатор до повышения привилегий, а затем воссоздает их после.Примерно так: https://sharepoint.stackexchange.com/questions/74205/spcontext-current-is-null-for-ihttphandler

ОДНАКО, случайно я обнаружил следующее.После получения идентификатора текущего сайта, например: var currentSiteId = SPContext.Current.Site.ID;

SPContext.Current больше не является нулевым позже, когда он находится внутри делегата с повышенными привилегиями!Кажется, что простой доступ к этому свойству до повышения привилегий также делает его доступным после!Странно !!!!

Так что фактически единственная строка кода, которую я добавил, была той, которую вы видели выше, даже без использования этой переменной позже!У меня такое ощущение, что где-то есть подвох!

...