2011-12-14 108 views
3

我想要设置一个WCF,该AJAX可以通过AJAX从我们的Sharepoint Foundation 2010站点上的自定义Web部件加载的JavaScript调用。为了简化Javascript端的处理,我想提供一个让Json回到调用者的Restful服务。当使用AJAX访问Sharepoint WCF时,SPContext.Current为空

问题是,当我用AJAX调用服务器时,SPContext.Current为空。

我使用MultipleBaseAddressWebServiceHostFactory中SVC文件来创建Web服务

<%@ 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" 
    %> 

合同为WebService是:

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

web服务的实现基本如下。

[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; 
    } 
} 

我核实,如果我叫web服务从web浏览器一切正常,而且我得到正确的数据备份。

我用下面的Ajax调用

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

用Firebug我已经验证正确的URL是从JavaScript调用,我已经在服务器端验证了正确的代码确实是达到了,但SPContext。当前为空。

Sharepoint服务器使用Windows和声明进行登录。这意味着实际的WCF将使用与Sharepoint解决方案不同的帐户运行,但由于我将其部署到vti_bin下面的文件夹,因此Sharepoint应向WCF提供其上下文。在我看来,AJAX调用不会触发Sharepoint提供其上下文,在某种意义上它是匿名的。

起初我以为Web服务本身是罪魁祸首,因为从browswer调用时会随机失败,但我觉得我整理这个问题了通过安装升级到SharePoint Foundation 2010

我怎样才能让来自javascript/a web服务的AJAX调用,它接受来自Javascript的AJAX调用,允许web服务访问已登录到Sharepoint站点的用户的上下文?

回答

5

我弄清楚了这个问题的解决方案,所以我想分享我的发现,以防其他人偶然发现这种问题。

基本问题是由于Microsofts svc工厂无法为ajax调用添加适合的访问绑定。这意味着vti_bin文件夹的验证魔术不会发生。你得到一个运行的svc,但没有Sharepoint上下文,当你从javascript访问javascript时,即使普通的访问工作正常。

您可以通过延长工厂解决该问题与正确的人

<%@ 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; 
      } 
     } 

    } 
} 

可能您可能想使用WebSc如果您希望在返回时包装结果,请使用riptEnablingBehavior而不是WebHttpBehavior。

还有一些额外的事情要考虑。网络上有一些迹象表明,缺少SP1也可能导致缺少Sharepoint上下文,因此如果遇到问题,请确认您拥有最新的Service Pack。

最后,如果您正在构建REST服务,可能会使用UriTemplate获取您所需的URL结构。不幸的是,在撰写本文时,UriTemplate在本场景中不受Microsoft的支持,因此在将设计基于UriTemplate的存在性之前,请调查此问题。

4

我面临使用SharePoint 2013年,我还没有尝试您的解决方案的机会,同样的问题,因为我读到一个又一个提升权限,然后后重建之前,基本上获得当前网站和网络ID 。类似这样的: https://sharepoint.stackexchange.com/questions/74205/spcontext-current-is-null-for-ihttphandler

然而,出于意外,我发现了以下内容。获取当前网站的ID后,如下所示: var currentSiteId = SPContext.Current.Site.ID;

SPContext.Current在升级特权委托内部之后不再是空的!看起来在提升权限之前访问这个属性也使得它在!奇怪的!!!!

所以实际上我添加的唯一一行代码就是你上面看到的代码,以后甚至不用这个变量!我有一种感觉,就是在某个地方抓到一个东西!

+0

这节省了我的一天!你摇滚:) – 2014-12-10 17:48:27

相关问题