可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This code produces a FileNotFoundException, but ultimately runs without issue:
void ReadXml()
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
//...
}
Here is the exception:
A first chance exception of type \'System.IO.FileNotFoundException\' occurred in mscorlib.dll
Additional information: Could not load file or assembly \'MyAssembly.XmlSerializers, Version=1.4.3190.15950, Culture=neutral, PublicKeyToken=null\' or one of its dependencies. The system cannot find the file specified.
It appears that the framework automatically generates the serialization assembly if it isn\'t found. I can generate it manually using sgen.exe, which alleviates the exception.
How do I get visual studio to generate the XML Serialization assembly automatically?
Update: The Generate Serialization Assembly: On setting doesn\'t appear to do anything.
回答1:
This is how I managed to do it by modifying the MSBUILD script in my .CSPROJ file:
First, open your .CSPROJ file as a file rather than as a project. Scroll to the bottom of the file until you find this commented out code, just before the close of the Project tag:
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets.
<Target Name=\"BeforeBuild\">
</Target>
<Target Name=\"AfterBuild\">
</Target>
-->
Now we just insert our own AfterBuild target to delete any existing XmlSerializer and SGen our own, like so:
<Target Name=\"AfterBuild\" DependsOnTargets=\"AssignTargetPaths;Compile;ResolveKeySource\" Inputs=\"$(MSBuildAllProjects);@(IntermediateAssembly)\" Outputs=\"$(OutputPath)$(_SGenDllName)\">
<!-- Delete the file because I can\'t figure out how to force the SGen task. -->
<Delete
Files=\"$(TargetDir)$(TargetName).XmlSerializers.dll\"
ContinueOnError=\"true\" />
<SGen
BuildAssemblyName=\"$(TargetFileName)\"
BuildAssemblyPath=\"$(OutputPath)\"
References=\"@(ReferencePath)\"
ShouldGenerateSerializer=\"true\"
UseProxyTypes=\"false\"
KeyContainer=\"$(KeyContainerName)\"
KeyFile=\"$(KeyOriginatorFile)\"
DelaySign=\"$(DelaySign)\"
ToolPath=\"$(TargetFrameworkSDKToolsDirectory)\"
Platform=\"$(Platform)\">
<Output
TaskParameter=\"SerializationAssembly\"
ItemName=\"SerializationAssembly\" />
</SGen>
</Target>
That works for me.
回答2:
As Martin has explained in his answer, turning on generation of the serialization assembly through the project properties is not enough because the SGen task is adding the /proxytypes
switch to the sgen.exe command line.
Microsoft has a documented MSBuild property which allows you to disable the /proxytypes
switch and causes the SGen Task to generate the serialization assemblies even if there are no proxy types in the assembly.
SGenUseProxyTypes
A boolean value that indicates whether proxy types
should be generated by SGen.exe. The SGen target uses this property to
set the UseProxyTypes flag. This property defaults to true, and there
is no UI to change this. To generate the serialization assembly for
non-webservice types, add this property to the project file and set it
to false before importing the Microsoft.Common.Targets or the
C#/VB.targets
As the documentation suggests you must modify your project file by hand, but you can add the SGenUseProxyTypes
property to your configuration to enable generation. Your project files configuration would end up looking something like this:
<PropertyGroup Condition=\" \'$(Configuration)|$(Platform)\' == \'Debug|x86\' \">
<!-- Snip... -->
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
<SGenUseProxyTypes>false</SGenUseProxyTypes>
</PropertyGroup>
<PropertyGroup Condition=\" \'$(Configuration)|$(Platform)\' == \'Release|x86\' \">
<!-- Snip... -->
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
<SGenUseProxyTypes>false</SGenUseProxyTypes>
</PropertyGroup>
回答3:
The other answers to this question have already mentioned the Project Properties->Build->Generate Serialization Assemblies setting but by default this will only generate the assembly if there are \"XML Web service proxy types\" in the project.
The best way to understand the exact behaviour of Visual Studio is to to examine the GenerateSerializationAssemblies target within the C:\\WINDOWS\\Microsoft.NET\\Framework\\v2.0.50727**Microsoft.Common.targets** file.
You can check the result of this build task from the Visual Studio Output window and select Build from the Show output from: drop down box. You should see something along the lines of
C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\bin\\sgen.exe /assembly:D:\\Temp\\LibraryA\\obj\\Debug\\LibraryA.dll /proxytypes /reference:.. /compiler:/delaysign-
LibraryA -> D:\\Temp\\LibraryA\\bin\\Debug\\LibraryA.dll
The key point here is the /proxytypes switch. You can read about the various switches for the XML Serializer Generator Tool (Sgen.exe)
If you are familiar with MSBuild you could customise the GenerateSerializationAssemblies target so that SGen task has an attribute of UseProxyTypes=\"false\" instead of true but
then you need to take on board all of the associated responsibility of customising the Visual Studio / MSBuild system. Alternatively you could just extend your build process to call SGen manually without the /proxytypes switch.
If you read the documentation for SGen they are fairly clear that Microsoft wanted to limit the use of this facility. Given the amount of noise on this topic, it\'s pretty clear that Microsoft did not do a great job with documenting the Visual Studio experience. There is even a Connect Feedback item for this issue and the response is not great.
回答4:
creating a new sgen task definition breaks a fly on the wheel. just set the needed variables to make the task work as intended. Anyway the microsoft documentation lacks some important info.
Steps to pre-generate serialization assemblies
(with parts from http://msdn.microsoft.com/en-us/library/ff798449.aspx)
- In Visual Studio 2010, in Solution Explorer, right-click the project for which you want to generate serialization assemblies, and then click Unload Project.
- In Solution Explorer, right-click the project for which you want to generate serialization assemblies, and then click Edit .csproj.
In the .csproj file, immediately after the <TargetFrameworkVersion>v?.?</TargetFrameworkVersion>
element, add the following elements:
<SGenUseProxyTypes>false</SGenUseProxyTypes>
<SGenPlatformTarget>$(Platform)</SGenPlatformTarget>
In the .csproj file, in each platform configuration
e.g. <PropertyGroup Condition=\"\'$(Configuration)|$(Platform)\' == \'Debug|x86\'\">
add the following line:
<GenerateSerializationAssemblies>On</GenerateSerializationAssemblies>
Save and close the .csproj file.
- In Solution Explorer, right-click the project you just edited, and then click Reload Project.
This procedure generates an additional assembly named .xmlSerializers.dll in your output folder. You will need to deploy this assembly with your solution.
Explanation
SGen by default only for proxy types generates for “Any CPU”. This happens if you don\'t set the according variables in your project file.
SGenPlatformTarget is required to match your PlatformTarget. I tend to think this is a bug in the project template. Why should the sgen target platform differ from your project\'s? If it does you will get a runtime exception
0x80131040: The located assembly\'s manifest definition does not match the assembly reference
You can locate the msbuild task definition by analyzing your project file:
<Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />
where MSBuildToolsPath depends on your <TargetFrameworkVersion>
http://msdn.microsoft.com/en-us/library/bb397428.aspx
Look inside the SGen task definition for TargetFrameworkVersion 4.0 from
Windows installation path\\Microsoft.NET\\Framework\\v4.0.30319\\Microsoft.CSharp.targets
to see the undocumented variables like $(SGenPlatformTarget) you are free to set in your project file
<Target
Name=\"GenerateSerializationAssemblies\"
Condition=\"\'$(_SGenGenerateSerializationAssembliesConfig)\' == \'On\' or (\'@(WebReferenceUrl)\'!=\'\' and \'$(_SGenGenerateSerializationAssembliesConfig)\' == \'Auto\')\"
DependsOnTargets=\"AssignTargetPaths;Compile;ResolveKeySource\"
Inputs=\"$(MSBuildAllProjects);@(IntermediateAssembly)\"
Outputs=\"$(IntermediateOutputPath)$(_SGenDllName)\">
<SGen
BuildAssemblyName=\"$(TargetFileName)\"
BuildAssemblyPath=\"$(IntermediateOutputPath)\"
References=\"@(ReferencePath)\"
ShouldGenerateSerializer=\"$(SGenShouldGenerateSerializer)\"
UseProxyTypes=\"$(SGenUseProxyTypes)\"
KeyContainer=\"$(KeyContainerName)\"
KeyFile=\"$(KeyOriginatorFile)\"
DelaySign=\"$(DelaySign)\"
ToolPath=\"$(SGenToolPath)\"
SdkToolsPath=\"$(TargetFrameworkSDKToolsDirectory)\"
EnvironmentVariables=\"$(SGenEnvironment)\"
SerializationAssembly=\"$(IntermediateOutputPath)$(_SGenDllName)\"
Platform=\"$(SGenPlatformTarget)\"
Types=\"$(SGenSerializationTypes)\">
<Output TaskParameter=\"SerializationAssembly\" ItemName=\"SerializationAssembly\"/>
</SGen>
</Target>
回答5:
In case someone else runs into this problem suddenly after everything was working fine before: For me it had to do with the \"Enable Just My Code (Managed Only)\" checkbox being unchecked in the options menu (Options -> Debugging) (which was automatically switched off after installing .NET Reflector).
EDIT:
Which is to say, of course, that this exception was happening before, but when \"enable just my code\" is off, the debugging assistant (if enabled), will stop at this point when thrown.
回答6:
I\'m a little late to the party, but I found the previous answer difficult to work with. Specifically Visual Studio would crash whenever I tried to view the properties of my project. I figure this was due to the fact that it no longer understood how to read the csproj file. That said...
Add the following to your post-build event command line:
\"C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.0A\\Bin\\NETFX 4.0 Tools\\sgen.exe\" \"$(TargetPath)\" /force
This will leverage sgen.exe directly to rebuild the Xml Serialization assembly every time you build your project for Debug or Release.
回答7:
Look in the properties on the solution. On the build tab at the bottom there is a dropdown called \"Generate Serialization assembly\"
回答8:
A slightly different solution from the one provided by brain backup could be to directly specify the platform target right where you have to use it like so:
<!-- Check the platform target value and if present use that for a correct *.XmlSerializer.dll platform setup (default is MSIL)-->
<PropertyGroup Condition=\" \'$(PlatformTarget)\'==\'\' \">
<SGenPlatform>$(Platform)</SGenPlatform>
</PropertyGroup>
<PropertyGroup Condition=\" \'$(PlatformTarget)\'!=\'\' \">
<SGenPlatform>$(PlatformTarget)</SGenPlatform>
</PropertyGroup>
<!-- Delete the file because I can\'t figure out how to force the SGen task. -->
<Delete Files=\"$(TargetDir)$(TargetName).XmlSerializers.dll\" ContinueOnError=\"true\" />
<SGen
BuildAssemblyName=\"$(TargetFileName)\"
BuildAssemblyPath=\"$(OutputPath)\"
References=\"@(ReferencePath)\"
ShouldGenerateSerializer=\"true\"
UseProxyTypes=\"false\"
KeyContainer=\"$(KeyContainerName)\"
KeyFile=\"$(KeyOriginatorFile)\"
DelaySign=\"$(DelaySign)\"
ToolPath=\"$(SGenToolPath)\"
SdkToolsPath=\"$(TargetFrameworkSDKToolsDirectory)\"
EnvironmentVariables=\"$(SGenEnvironment)\"
Platform=\"$(SGenPlatform)\">
<Output TaskParameter=\"SerializationAssembly\" ItemName=\"SerializationAssembly\" />
</SGen>