我正在尝试在服务器上备份文件,但其中一些正在使用中,无法打开.相反,如果当前副本正在使用中,我想打开它们的卷影副本.我怎样才能做到这一点?
作为参考,我使用的是C#.net 3.5.
我已经看过这个和这个问题,但它们都已经存在了几年,而在我的情况下,可能还有另一种解决方案:
我有一个ASP.NET MVC 5应用程序,带有基于THIS的插件系统.
所以我的~/bin文件夹是由框架复制的阴影,我的~/Plugins文件夹使用"手动阴影副本"到~/Plugins/ShadowCopy应用程序pre-init,如上面的链接所示.
到目前为止,这个工作正常,因为我现在有以下情况:
我创建了一个单独的受限制AppDomain来执行一些沙盒代码.
为了能够将我的程序集中定义的类型的对象传递给此域,我将此域设置为主域ApplicationBase的shadow-copy目录(如果不从那里加载它们,则SerializationException在将类型/对象传递给第二个时会得到一个domain,因为定义此类型的程序集是从不同位置加载的).
现在我可以将我的"基本程序集"中定义的类型传递给第二个域.
但是,只要我想使用插件中定义的类型,这就失败了,因为插件程序集不在默认的卷影副本目录中,而是在我的"手动卷影复制目录"中.
并且由于此目录也位于完全不同的位置,因此无法将其添加为PrivateBinPath基本路径下方.
目前我使用以下"解决方法":
#pragma warning disable 0618
AppDomain.CurrentDomain.SetShadowCopyPath(String.Join(";",
HostingEnvironment.MapPath("~/bin"),
HostingEnvironment.MapPath("~/Plugins/ShadowCopy")));
#pragma warning restore 0618
Run Code Online (Sandbox Code Playgroud)
在pre-init方法中.这将"手动阴影副本目录"添加到默认的阴影副本目录,我的插件也被框架阴影复制,我的第二个AppDomain能够加载它们,一切都在或多或少地起作用.
但正如SetShadowCopyPath我所描述的那样,我现在正在回答我的实际问题:
我正在寻找一种更好的解决方案来避免使用这种方法.
我想到了以下解决方案,但无法确定是否/如何可行:
AppDomain的AppDomainSetup.ShadowCopyDirectories属性~/bin~/Plugins/ShadowCopyweb.config ~/bin/Plugins并告诉IIS不回收主AppDomain文件夹中的更改(否则应用程序会在每次请求时重新启动,因为pre-init方法每次都会更改其中的文件)另一个想法是将"手动阴影副本目录"设置在默认的卷影副本目录下,所以不是~/Plugins/ShadowCopy类似的东西C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\69da84c5\cd056104\Plugins,但是"干扰框架文件夹"是明智的吗?
我愿意解决这个问题以及解决我的基本问题的不同方法.
开发VSS编写器应用程序:
在备份期间看到此错误,由Windows备份工具启动,是否有2155348129来自Microsoft的错误代码?
从"2010 - 07 - 20T02:54:19.354000000Z"开始的备份操作失败,因为创建正在备份的卷的卷影副本的卷影复制服务操作失败,并显示以下错误代码'2155348129 "
当VSSwriter服务(我的应用程序)停止时,不会发生这种情况.
任何帮助表示赞赏.在TechNet上找不到任何有用的东西.
Hackish解决方法:有趣的是备份工作是"windows分区处于活动状态".当然,这会使系统在重启时无法启动
从我到目前为止的理解,通过阅读这篇文档,例如:http://msdn.microsoft.com/en-us/library/ms404279.aspx,卷影复制是一项功能,允许使用的组件,而目前由应用程序加载.
从上面的doc:
公共语言运行库在加载程序集时锁定程序集文件,因此在卸载程序集之前无法更新该文件.从应用程序域卸载程序集的唯一方法是卸载应用程序域,因此在正常情况下,在卸载所有正在使用它的应用程序域之前,无法在磁盘上更新程序集.将应用程序域配置为卷影复制文件时,应用程序路径中的程序集将复制到另一个位置并从该位置加载.副本已锁定,但原始程序集文件已解锁并可以更新.
但似乎有时加载的程序集没有被锁定,因此Shadow副本没用.
为了说明这一点,我使用以下代码创建了一个简单的库A.dll:
using System;
public class A
{
public A()
{
Console.WriteLine("A");
}
}
Run Code Online (Sandbox Code Playgroud)
然后我将其加载到AppDomain中,代码如下:
using System;
using System.Reflection;
class Test
{
static void Main()
{
AppDomainSetup configuration = new AppDomainSetup
{
ShadowCopyFiles = "false"
};
AppDomain appDomain = AppDomain.CreateDomain("", null, configuration);
Console.WriteLine(appDomain.ShadowCopyFiles);
Assembly assembly = appDomain.Load("A");
assembly.CreateInstance("A");
Console.ReadLine();
assembly.CreateInstance("A");
}
}
Run Code Online (Sandbox Code Playgroud)
所以我期望当程序挂在ReadLine上时,我不应该使用A.dll程序集,但它似乎根本没有锁定:我甚至可以删除它!
所以这是我的问题:
1)为什么在此示例中加载的组件未锁定?
2)何时装配锁定,即阴影复制是否有用?
在此先感谢您的帮助.
无论如何Bin通过添加一些配置将文件夹(文件夹除外)标记为阴影复制web.config?
我不认为这Application_Start是一个安装的好地方,AppDomainSetup.ShadowCopyDirectories因为那时AppDomain已经加载了.
.Net中有ShadowCopy功能,可通过复制程序集来保护文件锁定.有两个属性:
AppDomain.ShadowCopyFiles 使用AppDomainSetupAppDomainSetup.ShadowCopyFiles 将其存储在内部 string[]AppDomainSetup有string Value[]字段,用于存储配置.对我来说奇怪的是,这AppDomainSetup.ShadowCopyFiles是一个字符串属性,我们需要设置"true"或"false"代替实际bool类型.
以下是该属性的实现AppDomainSetup:
public string ShadowCopyFiles
{
get
{
return this.Value[8];
}
set
{
if (value != null && string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0)
this.Value[8] = value;
else
this.Value[8] = (string) null;
}
}
Run Code Online (Sandbox Code Playgroud)
这是AppDomain.ShadowCopyFiles的实现:
public bool ShadowCopyFiles
{
get {
String s = FusionStore.ShadowCopyFiles;
if((s != null) &&
(String.Compare(s, "true", StringComparison.OrdinalIgnoreCase) == 0))
return true;
else
return false;
}
} …Run Code Online (Sandbox Code Playgroud) 我在部署网站时遇到问题。在之前的部署问题和部署站点后,卷影复制将被关闭。
特别是在部署时,我发现即使在复制app_offline.htm并验证站点/应用程序处于脱机状态之后,其中的文件也bin/*.dll经常被锁定。
appdomain关闭卷影复制后,我仍然希望在外观上卸载dll 时释放 dll 上的锁app_offline.htm。
我尝试部署一个临时web.config发现,Stack Overflow其目的是防止bin/在我尝试删除内容之前立即进行更改,甚至在复制新的内容后bin/
暂停。10sweb.config
?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<httpRuntime waitChangeNotification="300"
maxWaitChangeNotification="300"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)
我已通过handles util 确认我的应用程序池(w3wp.exe进程)是 dll 上的锁的持有者,因此我假设这就是我无法删除/覆盖文件的原因。如果我手动回收应用程序池,它会释放它,并且我能够很好地部署。不幸的是,作为部署过程的一部分,复制 app_offline 和更改 web.config 是可能的,但执行IISappcmd 回收则不行(出于权限/组策略原因),所以我真的需要能够仅通过app_offline.htm网络释放此锁。配置。
重新打开卷影复制确实可以“解决”这个特定问题,但如果 dll 上仍然持有锁定。然而我想知道/并担心我是否只是推迟了这个问题。appdomain除非再次加载时旧 dll 上的锁被释放?
复制进程 ID 时,app_offline.htm它w3wp不会像硬回收那样改变,但我认为它正在卸载appdomain应该释放bin/ files它已锁定的进程。
另一个有趣的点是,这似乎只发生在我们的生产服务器上,我无法在本地或我们的开发/登台站点上重新创建它。我不认为与app_pools或IIS …
Here's a small class I'm using to probe for a list of available plugins:
internal static class PluginDirectoryLoader
{
public static PluginInfo[] ListPlugins(string path)
{
var name = Path.GetFileName(path);
var setup = new AppDomainSetup
{
ApplicationBase = path,
ShadowCopyFiles = "true"
};
var appdomain = AppDomain.CreateDomain("PluginDirectoryLoader." + name, null, setup);
var exts = (IServerExtensionDiscovery)appdomain.CreateInstanceAndUnwrap("ServerX.Common", "ServerX.Common.ServerExtensionDiscovery");
PluginInfo[] plugins = null;
try
{
plugins = exts.ListPlugins(); // <-- BREAK HERE
}
catch
{
// to do
}
finally
{
AppDomain.Unload(appdomain);
}
return …Run Code Online (Sandbox Code Playgroud) 在下面的示例应用程序中,我创建了一个新的AppDomain,我执行它并启用了卷影复制.从新的AppDomain我然后尝试删除(替换)原来的主exe.但是我收到"访问被拒绝错误".有趣的是,在启动程序后,从Windows资源管理器中可以重命名主exe(但不能删除它).
阴影复制可以用于运行时覆盖主exe吗?
static void Main(string[] args)
{
// enable comments if you wanna try to overwrite the original exe (with a
// copy of itself made in the default AppDomain) instead of deleting it
if (AppDomain.CurrentDomain.IsDefaultAppDomain())
{
Console.WriteLine("I'm the default domain");
System.Reflection.Assembly currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
string startupPath = currentAssembly.Location;
//if (!File.Exists(startupPath + ".copy"))
// File.Copy(startupPath, startupPath + ".copy");
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = Path.GetFileName(startupPath);
setup.ShadowCopyFiles = "true";
AppDomain domain = AppDomain.CreateDomain(setup.ApplicationName, AppDomain.CurrentDomain.Evidence, setup);
domain.SetData("APPPATH", …Run Code Online (Sandbox Code Playgroud) 多年来,在进行编程时,我从未在该网站上发布过任何问题,但是我遇到了之前在此已解决的许多问题。但是现在,我遇到了一个似乎找不到答案的问题。
我正在创建一个应用程序,在该应用程序中我需要来自系统上的ShadowCopies的信息。我正在尝试通过使用WMI(在C#中)实现这一目标。但是,这给了我一个“初始化失败”的例外。这是代码:ManagementScope scope = new ManagementScope(“ \\。\ ROOT \ cimv2”);
//create object query
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_ShadowCopy");
//create object searcher
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(scope, query);
//get collection of WMI objects
ManagementObjectCollection queryCollection = searcher.Get();
//enumerate the collection.
foreach (ManagementObject m in queryCollection)
{
// access properties of the WMI object
Console.WriteLine("ClientAccessible : {0}", m["ClientAccessible"]);
}
Run Code Online (Sandbox Code Playgroud)
每当到达foreach行时,都会引发ManagementException并显示消息“ Initialization Failure”。我绝对不知道为什么会这样。如果我使用完全相同的代码并更改WMI类(更改为Win32_Processor / Win32_LogicalDisk / ...),则不会收到此异常,并且foreach循环可以正常工作。我还注意到,异常来自语句“ searcher.Get();”。我已经在Windows Server 2008计算机和Windows 7 Enterprise计算机上尝试了此代码,两者均生成相同的异常。
我也尝试过在vb脚本中使用此类,并且效果很好。VBS代码:
Set objWMIService = GetObject("winmgmts:\\" + ComputerName + …Run Code Online (Sandbox Code Playgroud) shadow-copy ×10
c# ×6
appdomain ×4
.net ×3
asp.net ×2
.net-3.5 ×1
assemblies ×1
backup ×1
clr ×1
deployment ×1
iis ×1
recovery ×1
reflection ×1
web-config ×1
windows ×1
wmi ×1