C# class 库中的用户控件(asp.net,ascx 文件),构建错误(aspnet_compiler.exe)
User Controls (asp.net, ascx-files) inside a C# class library, build error (aspnet_compiler.exe)
遇到问题 "passing" 来自 ASPNET_Compiler.exe 的错误:
错误 CS0103:名称 'TestMath' 在当前上下文中不存在。
从用户控件 (.cs) 文件在 TestMath 中调用的函数在上下文之外 (scope/namespace/...)。如果我注释掉在 TestMath 中调用方法的行,编译工作正常,我的用户控件(从 WebApplication 中引用 DLL)也是如此。
"TestMath"-class 是一个静态 class ,它包含一个静态方法 "Get",其中 returns -1+3 (我也有尝试将其创建为非静态...但运气不佳)。
Visual Studio (MSBuild) 中的正常构建工作正常,但众所周知;它没有将 .ascx 文件正确打包到 DLL 中。
我附上了一个 .rar 包含:
- 测试库
包含 1 个 .ascx 控件和 1 个数学 class
包含一个 post-构建事件,即 运行 是 "BuildAssembly.cmd",而 运行 是 aspnet_compiler 和 aspnet_merge .
- WebSite - 一个 .aspx 页面,用于显示库中的控件。
报错的行位于Label.ascx.cs内,第18行:
Lbl.Text += " MATH: " + TestMath.Get()
有什么建议吗?猜一下?禁止在 .ascx.cs 之外的 class 中调用方法?哦……不过话里有话!意思是说;如果我在用户控件 class 中复制 Math-class,像这样:
public class Label : UserControl
{
..methods of label
public class Math
{
public static Get()
}
}
解决方案确实可以编译,而且我可以在 classes 中调用方法...但是,正如我们都希望的那样;我也不例外:我也希望能够调用其他对象(我已经这样做了,它们只是存在于 GAC 中……)……所以,嗯……基本上; aspnet_compiler 在哪里寻找 dll 的...
下载示例解决方案:
http://s000.tinyupload.com/?file_id=76690332418132532036
如果你将解决方案解压到 C:\Solutions\Test,你可以 运行 它几乎没有麻烦,假设 Visual Studio 2010,Windows 7....NET 框架 4 或更高版本。
否则,这里有一些代码:
ASCX
<%@ Control Language="C#"
AutoEventWireup="true"
ClassName="TestLibrary.Controls.Label"
CodeFile="Label.ascx.cs"
CodeBehind="Label.ascx.cs"
Inherits="TestLibrary.Controls.LabelCode" %>
Test
<asp:Label runat="server" ID="Lbl"></asp:Label>
后面的ASCX代码
protected void Page_Load(object sender, EventArgs e)
{
Lbl.Text = "CodeBehindText...";
Lbl.Text += " MATH: " + TestMath.Get();
}
数学测试
public static int Get()
{
return -1 + 3;
}
BuildAssembly.cmd
SET compiler_path=%systemroot%\Microsoft.NET\Framework64\v4.0.30319
SET aspnet_merge=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
SET websiteproject=C:\Solutions\Test\TestLibrary\TestLibrary
SET compiled=C:\Solutions\Test\TestLibrary\TestLibrary\Compiled
SET outputfolder=C:\Solutions\Test\TestLibrary\TestLibrary\bin\Release
SET outputfilenamedll=TestLibrary.dll
%compiler_path%\aspnet_compiler.exe -p "%websiteproject%" -c -f -d -v / %compiled%
"%aspnet_merge%" %compiled% -o %outputfilenamedll%
COPY /Y %compiled%\bin\%outputfilenamedll% %outputfolder%\%outputfilenamedll%
RMDIR /s /q %compiled%
想知道为什么 "fuzz" 在 2015 年使用 ASCX?哦,希望重用几年前创建的 ascx 文件,将它们永久打包在库中,签署程序集,将其导入我的 SharePoint 环境...
又经过 4 小时的尝试和失败,这就是解决方案:
给你的ascx控件一个class名称(class名称,.ascx文件中的属性):
控制语言="C#" AutoEventWireup="true" CodeFile="~/Control.ascx.cs" Inherits="Control" ClassName="UnqiueControlName [must be different than the real class name]" %>
将所有自定义生成的 DLL 复制到 class 库的 BIN 文件夹。
或运行 cmd: gacutil /i
将自定义dll(例如:Common.dll)注册到gac中的途径,我试过了,但似乎又是一次浪费时间,因为apsnet_compiler似乎没有在所有 gac 文件夹中查找程序集(是的,不止一个 location/folder)。让我们不要忘记更新 GAC、MSIL、32 位、64 位……如果您在项目中引用 DLL,那么它会构建……稍后您更新 DLL,但忘记更新 GAC…… .并且在 运行 时应用程序将使用 GAC 中的 DLL...注册到 GAC 应该只能通过 Setup/real 安装...
- 像往常一样在 Visual Studio 中编译您的 class 库,其中包含 .ascx 文件。
将所有 .ascx 文件 "CodeBehind" 属性更改为 "CodeFile"(不能同时拥有,这是我在问题中的错误之一)
通过aspnet_compiler编译你的整个项目:
aspnet_compiler.exe -v 项目名称 -p "projectFolder (where csproj lives)" "outputFolder"
运行 aspnet_merge.exe 在 aspnet_compiler 创建的 "outputFolder" 上:
aspnet_merge.exe "outputFolder" -o "nameOfDLLYouWant.dll"
现在您有了一个包含 .ascx 文件的 dll,我们将所有 ascx 文件的 CodeFile 属性交换回 CodeBehind,以便智能感知和 MSBuild 正常工作。
创建一个新的 Web 应用程序项目,删除其中的所有内容,添加对新创建的 DLL 的引用并添加一个新的 Default.aspx.
在您的 .aspx 站点(或 web.conf 中)注册程序集和命名空间:
<%@ Register Assembly="UserControl" NameSpace="NameSpaceOfWhereYourControlLives" TagPrefix="uc">
添加你的正文标签,记得使用库中定义的 ClassName 属性的名称(.ascx 文件中的第一行)
或者一个简单的 cmd 文件,"does it all"(将需要的 DLL 复制到 Bin,在 CodeBehind、CodeFile 之间来回切换,将 dll 编译并合并为一个新的 dll):
@ECHO ON
setlocal enabledelayedexpansion
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::VARIABLES
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
SET project=C:\Solutions\UserControlLibrary
REM Notice that project variable above ends with project name below!
SET projectname=UserControlLibrary
SET projectcompiledfolder=C:\Temp\UserControlLibraryCompiled
SET outputdll=UserControlLibrary.dll
REM Configuration is either release or debug, depending on which "mode" you are building against in Visual studio.
SET projectconfiguration=Release
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::LOGIC
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
call:ReplaceFunction %project% "CodeBehind", "CodeFile"
call:CopyLibraryReference Common, Release, %project%
call:ProjectCompile %projectname%, %project%, %projectcompiledfolder%
call:ProjectMerge %projectcompiledfolder%, %outputdll%, %project%, %projectconfiguration%
call:ReplaceFunction %project% "CodeFile", "CodeBehind"
RMDIR /s /q %projectcompiledfolder%
exit
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
::FUNCTIONS
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
:CopyLibraryReference <referenceName> <referenceConfiguration> <project>
SET referenceName=%~1
SET referenceConfiguration=%~2
SET project=%~3
REM Solution folder, containing a bunch of Library projects, such as "Common", "ActiveDirectory", "BusinuessLogic" and our UserControlLibrary...
SET lib=C:\Solutions\
COPY /Y "%lib%%referenceName%\bin\%referenceConfiguration%\%referenceName%.dll" "%project%\bin\%referenceName%.dll"
goto:eof
:ProjectCompile <projectname> <project> <projectcompiledfolder>
SET projectname=%~1
SET project=%~2
SET projectcompiledfolder=%~3
REM Path to compiler might vary, also if you want 32 or 64 bit... this might need to change
SET compiler=C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe
"%compiler%" -v %projectname% -p "%project%" "%projectcompiledfolder%"
goto:eof
:ProjectMerge <projectcompiledfolder> <outputdll> <project> <projectconfiguration>
SET projectcompiledfolder=%~1
SET outputdll=%~2
SET project=%~3
SET projectconfiguration=%~4
REM Path to merger might vary, also if you want 32 or 64 bit... this might need to change
SET merger=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
"%merger%" "%projectcompiledfolder%" -o %outputdll%
COPY /Y "%projectcompiledfolder%\bin\%outputdll%" "%project%\bin\%projectconfiguration%\%outputdll%"
goto:eof
:ReplaceFunction <projectFolder> <replaceValue> <replaceWith>
set projectFolder=%~1
REM tempfile name can be anything...
set tempfile=%~1\replaceascxbuildv1.txt
set replaceValue=%~2
set replaceWith=%~3
for /f %%f in ('dir /b /s %projectFolder%\*.ascx') do (
for /f "tokens=1,* delims=¶" %%A in ( '"type %%f"') do (
SET string=%%A
SET modified=!string:%replaceValue%=%replaceWith%!
echo !modified! >> %tempfile%
)
del %%f
move %tempfile% %%f
)
goto:eof
将其添加到“.cmd”文件中,然后 运行 在 Post 生成事件时添加 cmd 文件。构建比平时慢(当然),所以你不必像我一样理解如果你有太多的用户控件,这会加起来。然后随意创建几个项目。 :P
结论:
现在我只需点击 build in Visual Studio,一切都是自动的,我终于可以写一些代码了!如果你自己使用过它,你需要做的就是找出你自己的文件和项目的路径,但请注意:一两个路径是在函数本身中编写的。 ;)
编辑:列表实际上是从 0 开始的,但我确实看到有两个 2...错误!
遇到问题 "passing" 来自 ASPNET_Compiler.exe 的错误:
错误 CS0103:名称 'TestMath' 在当前上下文中不存在。
从用户控件 (.cs) 文件在 TestMath 中调用的函数在上下文之外 (scope/namespace/...)。如果我注释掉在 TestMath 中调用方法的行,编译工作正常,我的用户控件(从 WebApplication 中引用 DLL)也是如此。
"TestMath"-class 是一个静态 class ,它包含一个静态方法 "Get",其中 returns -1+3 (我也有尝试将其创建为非静态...但运气不佳)。
Visual Studio (MSBuild) 中的正常构建工作正常,但众所周知;它没有将 .ascx 文件正确打包到 DLL 中。
我附上了一个 .rar 包含:
- 测试库
包含 1 个 .ascx 控件和 1 个数学 class
包含一个 post-构建事件,即 运行 是 "BuildAssembly.cmd",而 运行 是 aspnet_compiler 和 aspnet_merge .
- WebSite - 一个 .aspx 页面,用于显示库中的控件。
报错的行位于Label.ascx.cs内,第18行:
Lbl.Text += " MATH: " + TestMath.Get()
有什么建议吗?猜一下?禁止在 .ascx.cs 之外的 class 中调用方法?哦……不过话里有话!意思是说;如果我在用户控件 class 中复制 Math-class,像这样:
public class Label : UserControl
{
..methods of label
public class Math
{
public static Get()
}
}
解决方案确实可以编译,而且我可以在 classes 中调用方法...但是,正如我们都希望的那样;我也不例外:我也希望能够调用其他对象(我已经这样做了,它们只是存在于 GAC 中……)……所以,嗯……基本上; aspnet_compiler 在哪里寻找 dll 的...
下载示例解决方案: http://s000.tinyupload.com/?file_id=76690332418132532036
如果你将解决方案解压到 C:\Solutions\Test,你可以 运行 它几乎没有麻烦,假设 Visual Studio 2010,Windows 7....NET 框架 4 或更高版本。
否则,这里有一些代码: ASCX
<%@ Control Language="C#"
AutoEventWireup="true"
ClassName="TestLibrary.Controls.Label"
CodeFile="Label.ascx.cs"
CodeBehind="Label.ascx.cs"
Inherits="TestLibrary.Controls.LabelCode" %>
Test
<asp:Label runat="server" ID="Lbl"></asp:Label>
后面的ASCX代码
protected void Page_Load(object sender, EventArgs e)
{
Lbl.Text = "CodeBehindText...";
Lbl.Text += " MATH: " + TestMath.Get();
}
数学测试
public static int Get()
{
return -1 + 3;
}
BuildAssembly.cmd
SET compiler_path=%systemroot%\Microsoft.NET\Framework64\v4.0.30319
SET aspnet_merge=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
SET websiteproject=C:\Solutions\Test\TestLibrary\TestLibrary
SET compiled=C:\Solutions\Test\TestLibrary\TestLibrary\Compiled
SET outputfolder=C:\Solutions\Test\TestLibrary\TestLibrary\bin\Release
SET outputfilenamedll=TestLibrary.dll
%compiler_path%\aspnet_compiler.exe -p "%websiteproject%" -c -f -d -v / %compiled%
"%aspnet_merge%" %compiled% -o %outputfilenamedll%
COPY /Y %compiled%\bin\%outputfilenamedll% %outputfolder%\%outputfilenamedll%
RMDIR /s /q %compiled%
想知道为什么 "fuzz" 在 2015 年使用 ASCX?哦,希望重用几年前创建的 ascx 文件,将它们永久打包在库中,签署程序集,将其导入我的 SharePoint 环境...
又经过 4 小时的尝试和失败,这就是解决方案:
给你的ascx控件一个class名称(class名称,.ascx文件中的属性):
控制语言="C#" AutoEventWireup="true" CodeFile="~/Control.ascx.cs" Inherits="Control" ClassName="UnqiueControlName [must be different than the real class name]" %>
将所有自定义生成的 DLL 复制到 class 库的 BIN 文件夹。
或运行 cmd: gacutil /i
将自定义dll(例如:Common.dll)注册到gac中的途径,我试过了,但似乎又是一次浪费时间,因为apsnet_compiler似乎没有在所有 gac 文件夹中查找程序集(是的,不止一个 location/folder)。让我们不要忘记更新 GAC、MSIL、32 位、64 位……如果您在项目中引用 DLL,那么它会构建……稍后您更新 DLL,但忘记更新 GAC…… .并且在 运行 时应用程序将使用 GAC 中的 DLL...注册到 GAC 应该只能通过 Setup/real 安装...
- 像往常一样在 Visual Studio 中编译您的 class 库,其中包含 .ascx 文件。
将所有 .ascx 文件 "CodeBehind" 属性更改为 "CodeFile"(不能同时拥有,这是我在问题中的错误之一)
通过aspnet_compiler编译你的整个项目:
aspnet_compiler.exe -v 项目名称 -p "projectFolder (where csproj lives)" "outputFolder"
运行 aspnet_merge.exe 在 aspnet_compiler 创建的 "outputFolder" 上:
aspnet_merge.exe "outputFolder" -o "nameOfDLLYouWant.dll"
现在您有了一个包含 .ascx 文件的 dll,我们将所有 ascx 文件的 CodeFile 属性交换回 CodeBehind,以便智能感知和 MSBuild 正常工作。
创建一个新的 Web 应用程序项目,删除其中的所有内容,添加对新创建的 DLL 的引用并添加一个新的 Default.aspx.
在您的 .aspx 站点(或 web.conf 中)注册程序集和命名空间: <%@ Register Assembly="UserControl" NameSpace="NameSpaceOfWhereYourControlLives" TagPrefix="uc">
添加你的正文标签,记得使用库中定义的 ClassName 属性的名称(.ascx 文件中的第一行)
或者一个简单的 cmd 文件,"does it all"(将需要的 DLL 复制到 Bin,在 CodeBehind、CodeFile 之间来回切换,将 dll 编译并合并为一个新的 dll):
@ECHO ON
setlocal enabledelayedexpansion
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::VARIABLES
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
SET project=C:\Solutions\UserControlLibrary
REM Notice that project variable above ends with project name below!
SET projectname=UserControlLibrary
SET projectcompiledfolder=C:\Temp\UserControlLibraryCompiled
SET outputdll=UserControlLibrary.dll
REM Configuration is either release or debug, depending on which "mode" you are building against in Visual studio.
SET projectconfiguration=Release
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::LOGIC
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
call:ReplaceFunction %project% "CodeBehind", "CodeFile"
call:CopyLibraryReference Common, Release, %project%
call:ProjectCompile %projectname%, %project%, %projectcompiledfolder%
call:ProjectMerge %projectcompiledfolder%, %outputdll%, %project%, %projectconfiguration%
call:ReplaceFunction %project% "CodeFile", "CodeBehind"
RMDIR /s /q %projectcompiledfolder%
exit
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
::FUNCTIONS
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
:CopyLibraryReference <referenceName> <referenceConfiguration> <project>
SET referenceName=%~1
SET referenceConfiguration=%~2
SET project=%~3
REM Solution folder, containing a bunch of Library projects, such as "Common", "ActiveDirectory", "BusinuessLogic" and our UserControlLibrary...
SET lib=C:\Solutions\
COPY /Y "%lib%%referenceName%\bin\%referenceConfiguration%\%referenceName%.dll" "%project%\bin\%referenceName%.dll"
goto:eof
:ProjectCompile <projectname> <project> <projectcompiledfolder>
SET projectname=%~1
SET project=%~2
SET projectcompiledfolder=%~3
REM Path to compiler might vary, also if you want 32 or 64 bit... this might need to change
SET compiler=C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe
"%compiler%" -v %projectname% -p "%project%" "%projectcompiledfolder%"
goto:eof
:ProjectMerge <projectcompiledfolder> <outputdll> <project> <projectconfiguration>
SET projectcompiledfolder=%~1
SET outputdll=%~2
SET project=%~3
SET projectconfiguration=%~4
REM Path to merger might vary, also if you want 32 or 64 bit... this might need to change
SET merger=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
"%merger%" "%projectcompiledfolder%" -o %outputdll%
COPY /Y "%projectcompiledfolder%\bin\%outputdll%" "%project%\bin\%projectconfiguration%\%outputdll%"
goto:eof
:ReplaceFunction <projectFolder> <replaceValue> <replaceWith>
set projectFolder=%~1
REM tempfile name can be anything...
set tempfile=%~1\replaceascxbuildv1.txt
set replaceValue=%~2
set replaceWith=%~3
for /f %%f in ('dir /b /s %projectFolder%\*.ascx') do (
for /f "tokens=1,* delims=¶" %%A in ( '"type %%f"') do (
SET string=%%A
SET modified=!string:%replaceValue%=%replaceWith%!
echo !modified! >> %tempfile%
)
del %%f
move %tempfile% %%f
)
goto:eof
将其添加到“.cmd”文件中,然后 运行 在 Post 生成事件时添加 cmd 文件。构建比平时慢(当然),所以你不必像我一样理解如果你有太多的用户控件,这会加起来。然后随意创建几个项目。 :P
结论: 现在我只需点击 build in Visual Studio,一切都是自动的,我终于可以写一些代码了!如果你自己使用过它,你需要做的就是找出你自己的文件和项目的路径,但请注意:一两个路径是在函数本身中编写的。 ;)
编辑:列表实际上是从 0 开始的,但我确实看到有两个 2...错误!