La pagina di accesso personalizzata ha un spontext.current che è sempre nullo
-
10-12-2019 - |
Domanda
.trovato la soluzione
La soluzione è stata aggiungere una raccolta del sito root (poiché il codice era in esecuzione in un sito secondario, senza un sito root).
Vedi Questa soluzione
..Aggiornamento importante ( in base al feedback ricevuto così lontano )
Non ho Visual Studio installato sul server SharePoint 2013. Tutto il codice è compilato in Visual Studio 2012 utilizzando remoto i riferimenti alle DLL di SharePoint 2013 richieste e firmato digitalmente in modo da poter essere distribuito nella cache di assembly globale sul server SharePoint 2013.
al livello più elementare questa affermazione fallisce al punto di generazione
Page_Load()
;.SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback( SPContext.Current.Site.Zone );
Poiché
SPContext.Current
è Semprenull
.Sfondo
Il client ha bisogno del sito di SharePoint per essere accessibile utilizzando l'autenticazione basata su moduli per gli utenti esterni e l'autenticazione di Windows per gli utenti interni (Corporate). Sono passati e hanno configurato entrambi i fornitori di autenticazione e ora ottengono il segno predefinito.
Sebbene tutto ciò che funzioni autenticazione di Windows visualizza ancora la schermata di selezione del provider quando il client desidera che l'autenticazione di Windows passasse automaticamente e visualizzare una schermata di accesso di autenticazione basata su moduli se ciò non riesce.
Stato in difficoltà con questo per giorni dopo aver esaminato vari blog e articoli che sento che non sono più avanti e che è deprimente. Al momento non posso allenarti se mi manca qualcosa di veramente fondamentale.
Accedi personalizzati nella pagina
La pagina si basa su un'amaliazione di;
.
%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Login\default.aspx
%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Forms\default.aspx
Questo è solo un primo tentativo e realizzato che non avrà bisogno di tutti questi controlli alla fine, volevo solo vedere come le cose appendono insieme.
.<%@ Assembly Name="Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="SharepointIdentity" Namespace="Microsoft.SharePoint.IdentityModel" Assembly="Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Assembly Name="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> <%@ Page Language="C#" Inherits="MyCustomSignInModule.SignInForm, MyCustomSignInModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f2ae721af94bf9e9" MasterPageFile="~/_layouts/15/errorv15.master"%> <%@ Import Namespace="Microsoft.SharePoint.WebControls" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsLogonPageTitleInTitleArea" /> </asp:Content> <asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageTitle" /> </asp:Content> <asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsLogonPageMessage" /> <br /> <br /> <SharepointIdentity:LogonSelector ID="ClaimsLogonSelector" runat="server" /> <div id="SslWarning" style="color:red;display:none"> <SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageMessage" /> </div> <script language="javascript" > if (document.location.protocol != 'https:') { var SslWarning = document.getElementById('SslWarning'); SslWarning.style.display = ''; } </script> <asp:login id="signInControl" FailureText="<%$Resources:wss,login_pageFailureText%>" runat="server" width="100%"> <layouttemplate> <asp:label id="FailureText" class="ms-error" runat="server"/> <table width="100%"> <tr> <td nowrap="nowrap"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,login_pageUserName%>" EncodeMethod='HtmlEncode'/></td> <td width="100%"><asp:textbox id="UserName" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%" /></td> </tr> <tr> <td nowrap="nowrap"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,login_pagePassword%>" EncodeMethod='HtmlEncode'/></td> <td width="100%"><asp:textbox id="password" TextMode="Password" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%"/></td> </tr> <tr> <td colspan="2" align="right"><asp:button id="login" commandname="Login" text="<%$Resources:wss,login_pagetitle%>" runat="server" /></td> </tr> <tr> <td colspan="2"><asp:checkbox id="RememberMe" text="<%$SPHtmlEncodedResources:wss,login_pageRememberMe%>" runat="server" /></td> </tr> </table> </layouttemplate> </asp:login> <asp:label id="DebugText" class="ms-error" runat="server"/> </asp:Content>
MycustomsigninModule Assembly
.using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Microsoft.IdentityModel.Web; using Microsoft.SharePoint; using Microsoft.SharePoint.IdentityModel; using Microsoft.SharePoint.IdentityModel.Pages; using Microsoft.SharePoint.Administration; using Microsoft.SharePoint.Administration.Claims; using Microsoft.SharePoint.ApplicationRuntime; using Microsoft.SharePoint.Diagnostics; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.WebControls; using System.IdentityModel.Tokens; using System.Web.Configuration; namespace MyCustomSignInModule { public class SignInForm : FormsSignInPage { protected Label DebugText; private static SPIisSettings _iisSettings; internal static SPIisSettings iisSettings { get { if (_iisSettings == null) { SPSecurity.RunWithElevatedPrivileges(delegate() { _iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone); }); } return _iisSettings; } } protected void Page_Load(object sender, EventArgs e) { HttpRequest request = HttpContext.Current.Request; bool isWindowsAuth = false; string username = request["username"]; string password = request["password"]; // If no username is provided, it'll probably be Windows Authentication (NTLMv2 protocol) if (String.IsNullOrEmpty(username)) { isWindowsAuth = true; } try { //SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default]; if (isWindowsAuth) { // Windows Authentication it is if (iisSettings.UseWindowsClaimsAuthenticationProvider) { SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider; RedirectToLoginPage(provider); // This should cause automatic sign in } } else { // FBA authentication it is. SPFormsAuthenticationProvider formsClaimsAuthenticationProvider = iisSettings.FormsClaimsAuthenticationProvider; SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url), formsClaimsAuthenticationProvider.MembershipProvider, formsClaimsAuthenticationProvider.RoleProvider, username, password, SPFormsAuthenticationOption.PersistentSignInRequest); if (null != token) { EstablishSessionWithToken(token); base.RedirectToSuccessUrl(); } } } catch (Exception ex) { DebugText.Text = ex.ToString(); } } // Microsoft.SharePoint.IdentityModel.LogonSelector private void RedirectToLoginPage(SPAuthenticationProvider provider) { string components = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped); string url = provider.AuthenticationRedirectionUrl.ToString(); if (provider is SPWindowsAuthenticationProvider) { components = EnsureUrlSkipsFormsAuthModuleRedirection(components, true); } SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, components); } // Microsoft.SharePoint.Utilities.SPUtility private string EnsureUrlSkipsFormsAuthModuleRedirection (string url, bool urlIsQueryStringOnly) { if (!url.Contains("ReturnUrl=")) { if (urlIsQueryStringOnly) { url = url + (string.IsNullOrEmpty(url) ? "" : "&"); } else { url = url + ((url.IndexOf('?') == -1) ? "?" : "&"); } url = url + "ReturnUrl="; } return url; } // Microsoft.SharePoint.IdentityModel.Pages.IdentityModelSignInPageBase private void EstablishSessionWithToken(SecurityToken securityToken) { if (securityToken == null) { throw new ArgumentNullException("securityToken"); } SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current; if (fam == null) { throw new InvalidOperationException(); } fam.SetPrincipalAndWriteSessionToken(securityToken); } private SPAuthenticationProvider GetAuthenticationProvider(string providerName) { SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default]; foreach (SPAuthenticationProvider currentProvider in iisSettings.ClaimsAuthenticationProviders) { if (currentProvider.DisplayName.ToLower() == providerName.ToLower()) { return currentProvider; } } return null; } } }
Il processo
Ho un'istanza di SharePoint di test in esecuzione sulla VM ma non è stato installato Visual Studio poiché tutto lo sviluppo è fatto da remoto. Il processo corrente che seguo;
.
- Build C # Library Class (questo sarà
MyCustomSignInModule.Dll
)- Iscriviti
MyCustomSignInModule.Dll
in modo che possa essere posizionato nel VM GAC.- Registrati
MyCustomSignInModule.Dll
nel GAC sull'istanza VM.- Salva
SignInForm.aspx
nel%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\
che è l'equivalente della directory virtuale<SharePointSiteRoot>/_layouts/
in IIS.- Nel sito di Amministrazione centrale SharePoint Impostare il registro personalizzato nella pagina sulla mia pagina
~/_layouts/SignInForm.aspx
.- Reset IIS usando
iisreset
.- Test Accesso al sito di SharePoint (è qui che cade).
il problema
Se non è chiaro che l'errore è;
.System.NullReferenceException: Object reference not set to an instance of an object. at MyCustomSignInModule.SignInForm.b__0() at Microsoft.SharePoint.SPSecurity.<>c__DisplayClass5.b__3() at Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode) at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param) at Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode) at MyCustomSignInModule.SignInForm.get_iisSettings() at MyCustomSignInModule.SignInForm.Page_Load(Object sender, EventArgs e)
spontext.current è nullo perché?
Il
NullReferenceException
viene causato daSPContext.Current
essendo nullo, ma non posso allenarmi perché è nullo e nessuna quantità di articoli che ho guardato che hanno portato finora per aiutarmi a risolvermi questo. Spero postare il mio intero processo qui qualcuno potrebbe essere in grado di indicarmi quello che mi manca o sbagliata.
Soluzione
Finally got to the bottom of what was causing the issue, firstly would like to thank both @MdMazzotti and @Hugh Wood for their persistent help.
In the end I stumbled on the fix which turned out to be partly because the way the site was built. In my particular case the site was built as a sub-site in SharePoint, for whatever reason this meant there was no Site Collection at the root of the SharePoint website which was the cause of the Null
SPContext
in my code.
After adding a Root Site Collection my code began to work as expected.
Altri suggerimenti
I'm just guessing here, but here are some things that I think could help.
Add this JavaScript code to the custom sign in page (before your if-statement):
SP.SOD.executeFunc('SP.js', 'SP.ClientContext');
You could also add this JavaScript to your page to test if it works or not, using the console:
var clientContext = new SP.ClientContext.get_current();
console.log(clientContext);
If it returns something, then we have progress! If not, then I'll have to continue my search, since I find your question interesting.
EDIT
Instead of using this server-side code:
if (_iisSettings == null)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
_iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
});
}
return _iisSettings;
Try using this instead:
if (_iisSettings == null)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
_iisSettings = Microsoft.SharePoint.SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(Microsoft.SharePoint.SPContext.Current.Site.Zone);
});
}
return _iisSettings;
I searched around and noticed that in some of the code examples I encountered, the _iisSettings was different from yours. Perhaps that is why your SPContext.Current is null?
Please check this answer: https://stackoverflow.com/questions/5081251/how-can-this-throw-a-nullreferenceexception
SPContext.Current doesn't work under Elevated Privileges, so you have to rewrite like in the answer above.
Can you check this MSDN article: http://msdn.microsoft.com/en-us/library/office/ms468609(v=office.14).aspx
I think because you use a C# Class Library project in Visual studio, you are not in a web context and can't use SPContext.Current as explained in the MSDN article above.