기능 Deactivation 2013 중 프로그래밍 방식으로 사용자 정의 마스터 페이지를 삭제할 수 없습니다.
문제
현재 사이트 범위에 배포되는 사용자 정의 마스터 페이지가 있습니다. 배포되고 기능이 활성화되면 마스터 페이지가 사용할 수 있습니다. 기능을 활성화하고 사이트에서 마스터 페이지를 설정하고 하위 사이트가 마스터 페이지를 올바르게 상속받을 수 있습니다.
피쳐를 비활성화하려고 시도 할 때 문제가 발생합니다.
피쳐의 마스터 페이지가 설정된 모든 사이트를 찾아서 기본 마스터 페이지로 다시 설정하는 이벤트 수신기가 있습니다. 이는 또한 사이트 상속 사이트에 마스터 페이지를 설정하는 데 포함됩니다.
이 작업을 완료 한 후에는 마스터 페이지 갤러리에서 마스터 페이지를 삭제하고 여전히 사용 중임을 나타내는 오류가 발생했습니다. GUI를 통해 사이트를 확인할 때 모든 것이 시애틀으로 돌아가고 상속 된 사이트가 부모로부터 상속되고 있으므로 모든 것이 그 끝에서 괜찮아 보입니다.
사이트 모음의 내용 및 구조 에 들어가면 마스터 페이지 관련 페이지를 조회하면 _devicechannelmappings.aspx 페이지와 여전히 관계가 있습니다. 상위에서 마스터 페이지를 상속하는 사이트입니다. 아래 참조 :
나는이 관계를 제거하기 위해 프로그래밍 방식으로 프로그래밍 방식으로 찾을 수 없었으며 카탈로그 라이브러리에서 마스터 페이지를 삭제할 수 없기 때문에
GUI의 루트 사이트 모음으로 이동하여 을 확인하면 모든 사이트 마스터 페이지 설정 을 상속하여 관계가 사라집니다. 삭제하려면.
어떤 도움도 감사 할 것입니다. 다음은 기능 비활성화를위한 현재 코드입니다.
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
using (SPSite siteCollection = (SPSite)properties.Feature.Parent)
{
string defaultMasterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl.EndsWith("/") ? siteCollection.ServerRelativeUrl : siteCollection.ServerRelativeUrl + "/" , "_catalogs/masterpage/seattle.master");
string pulseMasterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl.EndsWith("/") ? siteCollection.ServerRelativeUrl : siteCollection.ServerRelativeUrl + "/" , "_catalogs/masterpage/pulse.v01.master");
foreach (SPWeb web in siteCollection.AllWebs)
{
Hashtable hash = web.AllProperties;
if (hash["__InheritsMasterUrl"].ToString() == "True" && !web.IsRootWeb)
{
web.MasterUrl = web.ParentWeb.MasterUrl;
web.Update();
}
else if (web.MasterUrl == pulseMasterUrl)
{
web.MasterUrl = defaultMasterUrl;
web.Update();
}
if (hash["__InheritsCustomMasterUrl"].ToString() == "True" && !web.IsRootWeb)
{
web.CustomMasterUrl = web.ParentWeb.CustomMasterUrl;
web.Update();
}
else if (web.CustomMasterUrl == pulseMasterUrl)
{
web.CustomMasterUrl = defaultMasterUrl;
web.Update();
}
}
foreach (SPWeb web in siteCollection.AllWebs)
{
try
{
SPFile file = web.GetFile(pulseMasterUrl);
if (file.Exists)
{
file.Delete();
}
file.Update();
}
catch (Exception ex)
{
}
}
}
}
. 해결책 2
이 문제를 해결하는 가장 좋은 방법인지 모르지만 에서 을 수동으로 편집하여 문제를 해결할 수있었습니다 기능 비활성화 .이렇게하면 매핑이 사용자 정의 마스터 페이지에 삭제되고 삭제할 수 있습니다.
여기에 최종 코드가 있습니다 :
public class PulseMasterPageEventReceiver : SPFeatureReceiver
{
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
using (SPSite siteCollection = (SPSite)properties.Feature.Parent)
{
string defaultMasterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl.EndsWith("/") ? siteCollection.ServerRelativeUrl : siteCollection.ServerRelativeUrl + "/" , "_catalogs/masterpage/seattle.master");
string pulseMasterUrl = SPUrlUtility.CombineUrl(siteCollection.ServerRelativeUrl.EndsWith("/") ? siteCollection.ServerRelativeUrl : siteCollection.ServerRelativeUrl + "/" , "_catalogs/masterpage/pulse.v01.master");
foreach (SPWeb web in siteCollection.AllWebs)
{
web.AllowUnsafeUpdates = true;
Hashtable hash = web.AllProperties;
if (hash["__InheritsMasterUrl"].ToString() == "True" && !web.IsRootWeb)
{
web.MasterUrl = web.ParentWeb.MasterUrl;
web.Update();
}
else if (web.MasterUrl == pulseMasterUrl)
{
web.MasterUrl = defaultMasterUrl;
web.Update();
}
if (hash["__InheritsCustomMasterUrl"].ToString() == "True" && !web.IsRootWeb)
{
web.CustomMasterUrl = web.ParentWeb.CustomMasterUrl;
web.Update();
}
else if (web.CustomMasterUrl == pulseMasterUrl)
{
web.CustomMasterUrl = defaultMasterUrl;
web.Update();
}
web.AllowUnsafeUpdates = false;
}
foreach (SPWeb web in siteCollection.AllWebs)
{
string deviceChannelMappings = SPUrlUtility.CombineUrl(web.Url.EndsWith("/") ? web.Url : web.Url + "/", "_catalogs/masterpage/__devicechannelmappings.aspx");
SPFile dcmFile = web.GetFile(deviceChannelMappings);
Stream dcmFileStream = dcmFile.OpenBinaryStream();
Stream dcmFileWrite = new MemoryStream();
using (StreamWriter sw = new StreamWriter(dcmFileWrite))
using (StreamReader sr = new StreamReader(dcmFileStream))
{
string line;
bool foundCorrection = false;
while ((line = sr.ReadLine()) != null)
{
if (line.Contains("pulse.v01.master"))
{
foundCorrection = true;
line = line.Replace("pulse.v01.master", "seattle.master");
}
sw.WriteLine(line);
}
sw.Flush();
if (foundCorrection)
{
if (dcmFile.CheckOutType != SPFile.SPCheckOutType.None)
dcmFile.UndoCheckOut();
if (dcmFile.RequiresCheckout)
{
dcmFile.CheckOut();
dcmFile.SaveBinary(dcmFileWrite);
dcmFile.CheckIn("Updated master page references to default.");
}
else
{
dcmFile.SaveBinary(dcmFileWrite);
}
if (dcmFile.Level == SPFileLevel.Draft)
{
dcmFile.Publish("Updated master page references to default.");
}
dcmFile.Update();
}
}
}
foreach (SPWeb web in siteCollection.AllWebs)
{
try
{
SPFile file = web.GetFile(pulseMasterUrl);
if (file.Exists)
{
file.Delete();
}
file.Update();
}
catch (Exception ex)
{
}
}
}
}
. 다른 팁
는 사이트 전체에서 장치 채널에서 마스터 페이지가 사용되고있는 것처럼 보입니다.Microsoft는 장치 채널에 대해 구성된 마스터 페이지를 보거나 수정하기위한 공용 API를 제공하지 않습니다.그게, 내 책 (SharePoint 2013 WCM 고급 요리 책 : http://tinyurl.com/lutktay ),구성된 마스터 페이지를 보거나 수정하는 방법에 대한 샘플이 있습니다.
여기에 장치 채널을 보는 C # 샘플 코드가 있습니다.
namespace Code6587EN.Ch02.GetDeviceChannelMaps
{
using Microsoft.SharePoint;
using System;
using System.Collections;
using System.Reflection;
/// <summary>
/// Console Application to get the Device Channel mappings for each
/// Site in a Site Collection
/// </summary>
class Program
{
static void Main(string[] args)
{
// Get the Site Collection in a Using statement
using (var site = new SPSite("http://sharepoint/sitecollection"))
{
// Get the Mappings File type and constructor
var typeMappingFile = Type.GetType("Microsoft.SharePoint.Publishing.Mobile.MasterPageMappingsFile, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
var consMappingFile = typeMappingFile.GetConstructor(new Type[] {typeof(SPWeb), typeof(bool), typeof(SPWeb)});
// Iterate through each Site in the Site Collection
foreach (SPWeb web in site.AllWebs)
{
// Ensure the Site exists
if (web.Exists)
{
// Get the Mapping File for the Site
var mappingFile = consMappingFile.Invoke(new object[] { web, false, null });
// Output the Default channel details
Console.WriteLine("");
Console.WriteLine("Site: " + web.Url);
Console.WriteLine("Device Channel: Default");
Console.WriteLine("Master Page: " + web.CustomMasterUrl);
// Get the mappings field from the Mapping File and cast as the IDictionary interface
var mappings = (IDictionary)typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mappingFile);
// Iterate through each key in the IDictionary
foreach (var key in mappings.Keys)
{
// Get the Master Page Url property from the mapping object
var mappingObject = mappings[key];
var masterUrl = (string)mappingObject.GetType().GetProperty("MasterPageUrl", BindingFlags.Instance | BindingFlags.Public).GetValue(mappingObject, null);
// Output the Channel details
Console.WriteLine("");
Console.WriteLine("Site: " + web.Url);
Console.WriteLine("Device Channel: " + key);
Console.WriteLine("Master Page: " + masterUrl);
}
// Dispose the Site object
web.Dispose();
}
}
}
// Wait for a key to be pressed before closing the application
Console.WriteLine("Press Any Key to Continue...");
Console.Read();
}
}
}
.
여기에는 장치 채널 설정을위한 C # 샘플 코드가 있습니다.
namespace Code6587EN.Ch02.ApplyMasterToChannel
{
using Microsoft.SharePoint;
using System;
using System.Collections;
using System.Reflection;
/// <summary>
/// Console Application to apply a Master Page to a Device Channel
/// </summary>
class Program
{
static void Main(string[] args)
{
// Get the Site Collection in a Using statement
using (var site = new SPSite("http://sharepoint/sitecollection"))
{
// Get the Mappings File type and constructor
var typeMappingFile = Type.GetType("Microsoft.SharePoint.Publishing.Mobile.MasterPageMappingsFile, Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
var consMappingFile = typeMappingFile.GetConstructor(new Type[] {typeof(SPWeb), typeof(bool), typeof(SPWeb)});
// Get the root Site in a Using statement
using (var web = site.RootWeb)
{
// Get the Mapping File
var mappingFile = consMappingFile.Invoke(new object[] { web, false, null });
// Get the Mappings and cast to an IDictionary
var mappings = (IDictionary)typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mappingFile);
// Set the Master Page Url of the mapping object
mappings["PowerShell"].GetType().GetProperty("MasterPageUrl", BindingFlags.Instance | BindingFlags.Public).SetValue(mappings["PowerShell"], "/_catalogs/masterpage/seattle.master", null);
// Set the updated Mappings on the Mappings file
typeMappingFile.GetField("mappings", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(mappingFile, mappings);
// Get and invoke the Update Single Channel method
var updateMethod = typeMappingFile.GetMethod("UpdateSingleChannel", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
updateMethod.Invoke(mappingFile, new object[] { "PowerShell" });
}
}
// Wait for a key to be pressed before closing the application
Console.WriteLine("Press Any Key to Continue...");
Console.Read();
}
}
}
.
이 두 가지 샘플을 사용하면 각 사이트마다 장치 채널을 가져와 마스터 페이지를 사용하지 않도록 해야하는 작업이 있어야합니다.