- PR -

ASP.NETで動的コンパイル時のクラスモジュールの指定

1
投稿者投稿内容
なかむら
ベテラン
会議室デビュー日: 2001/10/22
投稿数: 67
投稿日時: 2003-06-14 00:10
VS.NETでASP.NETの開発をしていますが、サーバの関係上ビルド済みDLLをアップロードできないため、動的コンパイルして実行されるようにPageディレクティブを修正しています。

<%@ Page language="VB"
  Codebehind="WebForm1.aspx.vb"
  AutoEventWireup="false"
  Inherits="WebApplication1.WebForm1" %>

    ↓

<%@ Page language="VB"
  Codebehind="WebForm1.aspx.vb"
  Src="WebForm1.aspx.vb"
  AutoEventWireup="false"
  Inherits="WebApplication1.WebForm1" %>

こうして動的コンパイルするようにした場合、別のクラスモジュールなどを使用する場合の指定の方法がわからなくて困っています。

<%@ Assembly Src="Class1.vb" %>

と記述してもやはりクラスを参照しているところでコンパイルエラーになります。
どうすればよいのかご存知の方いらっしゃいませんでしょうか?
NothingButXMLInfoSet
ベテラン
会議室デビュー日: 2003/03/31
投稿数: 65
投稿日時: 2003-06-14 07:32
Class1.vbのクラスが名前空間に属しているにもかかわらず、その名前空間の省略を宣言(Imports)するのを忘れていませんか?例えば次のaspxとaspx.vbがあるとき、

コード:
Namespace WebApplication1
Public Class WebForm1 : Inherits System.Web.UI.Page

End Class
End Namespace

コード:
<%@Page Language="VB"
  Codebehind="WebForm1.aspx.vb" 
  Src="WebForm1.aspx.vb" 
  AutoEventWireup="false" 
	Inherits="WebApplication1.WebForm1" %> 
<%@Assembly Src="Class1.vb"%>
<%
Response.Write(Class1.s)
%>


次のClass1.vbを使うとコンパイルエラーです。

コード:
Namespace WebApplication1
Public Class Class1
Public Shared s As String = "test"
End Class
End Namespace


この場合、Response.Writeの記述を「Response.Write(WebApplication1.Class1.s)」に変えるか、aspxの先頭に「<%@Import Namespace="WebApplication1"%>」のディレクティブを配置しなければなりません。
GUNNM
常連さん
会議室デビュー日: 2002/01/23
投稿数: 30
お住まい・勤務地: 横浜
投稿日時: 2003-06-14 11:04
私も同様の経験があります。私が調べた限りでは、コードビハインドしたときに他のCSファイル内のコードとリンクを張ることは不可能です。Cで言うリンカーの設定方法があればよいのですが。。。

私の対処作は、「はっきり言って、お勧めすることができるレベルではない」ものですが、「基本的にASPXとCSを別ファイルにしない」というものです。かなり生産性が落ちます。ASPXに<script runat="server" src="hogehoge.cs">などとかくと、CSファイルを読み込むことができますが、結局、継承元であるソース(Inheritsするクラス)からは、それらのコードを見ることはできません。ま、当たり前かもしれませんが。。。

でも、PageディレクティブにSrc=で指定したCSファイル内に書いたクラスは読むことはできるから、nmakeで、ファイル自体を結合してから、UPすることができるかな。と最近考えています。これが確立されれば、UPされているファイルは、いろんなCSファイルに同じクラスが定義されているけど、開発環境や、ソース管理上は、1ファイル1クラスです。。。
なかむら
ベテラン
会議室デビュー日: 2001/10/22
投稿数: 67
投稿日時: 2003-06-15 01:41
引用:

NothingButXMLInfoSetさんの書き込み (2003-06-14 07:32) より:
Class1.vbのクラスが名前空間に属しているにもかかわらず、その名前空間の省略を宣言(Imports)するのを忘れていませんか?例えば次のaspxとaspx.vbがあるとき、



VS.NETで何も考えずにサクっとプロジェクトを作成した場合、各ソースにNamespaceってつかないのですが、本来ビルドされる場合は、プロジェクトファイル内に記述されたNamespaceでビルドされているのでしょうか?

で、各ソースに手動にてNamespaceを指定し、aspxの先頭に@Assemblyディレクティブを追加後、

 Dim objClass As New WebApplication1.Class1()

としてインスタンス化させようとしても、「WebApplication1.Class1が定義されていません」と表示されてしまいます。
@Inportディレクティブを指定しても同じでした・・・。
NothingButXMLInfoSet
ベテラン
会議室デビュー日: 2003/03/31
投稿数: 65
投稿日時: 2003-06-15 07:35
Class1.vbがプロジェクトに含まれているのなら、プロジェクトのプロパティで指定されている名前空間に属することになります。ソースに名前空間を追加すると、「プロジェクトの名前空間.ソースの名前空間.クラス名」になります。
GUNNM
常連さん
会議室デビュー日: 2002/01/23
投稿数: 30
お住まい・勤務地: 横浜
投稿日時: 2003-06-15 18:10
動的コンパイルの場合、クラスファイル同士がリンクされないため、クラスファイルから他のクラスファイルを見ることはできません。ASPXにどんなディレクティブを記述しても、InheritsされたASPX内で見ることができるだけで、Inheritsもとになるクラスファイルでは、見えないのです。派生関係のクラスにおいて、子供のクラスに設定した内容を親クラスから見に行くのが不可能なように、ページで設定したものは、ASPXファイルでしか見えないのです。ただし、<script runat=server src=hoge.cs></script>のように、ASPXファイル内のソースの一部として取り込むようにすれば大丈夫です。
NothingButXMLInfoSet
ベテラン
会議室デビュー日: 2003/03/31
投稿数: 65
投稿日時: 2003-06-15 22:30
やっと事態が飲み込めました。このまま「できません」だと悔しいので、対策を考えました。もしWebサーバーのbinフォルダに書き込み権限があるようなら、次のコードでアセンブリをコンパイルして参照できます。

コード:
'--WebForm1.aspx.vb--
Imports System
Imports System.Reflection
Imports System.IO
Namespace WebApplication1
Public Class WebForm1 : Inherits System.Web.UI.Page
Public Sub Page_Load(o As Object, e As System.EventArgs)
Dim provider As New Microsoft.VisualBasic.VBCodeProvider()
Dim vbc As System.CodeDom.Compiler.ICodeCompiler = provider.CreateCompiler()
Dim opt As New System.CodeDom.Compiler.CompilerParameters(Nothing, Server.MapPath("bin\Class1.dll"))
Dim res As System.CodeDom.Compiler.CompilerResults = vbc.CompileAssemblyFromFile(opt, Server.MapPath("Class1.vb"))
Dim s As String
For Each s In res.Output
Response.Write(s)
Response.Write("<br>")
Next
Dim asm As [Assembly] = [Assembly].Load("Class1, version=0.0.0.0, culture=neutral, publickeyToken=null")
Dim t As Type = asm.GetType("WebApplication1.Class1")
Dim obj As Object = asm.CreateInstance("WebApplication1.Class1")
Response.Write(CType(t.InvokeMember("s", BindingFlags.DeclaredOnly Or BindingFlags.Public Or Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, obj, Nothing), String))
End Sub
End Class
End Namespace



コード:
'--Class1.vb--
Namespace WebApplication1
Public Class Class1
Public Function s As String
Return "test"
End Function
End Class
End Namespace



コード:
'--WebForm1.vb--
<%@Page Language="VB"
Codebehind="WebForm1.aspx.vb" 
Src="WebForm1.aspx.vb" 
AutoEventWireup="true" 
Inherits="WebApplication1.WebForm1" %> 


binフォルダに書き込みできない場合は、次のコードが使えるでしょうが、この場合はASP.NETの特徴である「DLLをいつでも上書きできる」というメリットが教授できなくなります(Webサーバーを停止しなければならない)。

コード:
Imports System
Imports System.Reflection
Imports System.IO
Namespace WebApplication1
Public Class WebForm1 : Inherits System.Web.UI.Page
Public Sub Page_Load(o As Object, e As System.EventArgs)
Dim loc As String = [Assembly].GetExecutingAssembly().Location
Dim dir As String = loc.SubString(0, loc.LastIndexOf("\"))
If Not (File.Exists(dir & "\Class1.dll"))
Dim provider As New Microsoft.VisualBasic.VBCodeProvider()
Dim vbc As System.CodeDom.Compiler.ICodeCompiler = provider.CreateCompiler()
Dim opt As New System.CodeDom.Compiler.CompilerParameters(Nothing, dir & "\Class1.dll")
Dim res As System.CodeDom.Compiler.CompilerResults = vbc.CompileAssemblyFromFile(opt, Server.MapPath("Class1.vb"))
Dim s As String
For Each s In res.Output
Response.Write(s)
Response.Write("<br>")
Next
End If
Dim asm As [Assembly] = [Assembly].Load("Class1, version=0.0.0.0, culture=neutral, publickeyToken=null")
Dim t As Type = asm.GetType("WebApplication1.Class1")
Dim obj As Object = asm.CreateInstance("WebApplication1.Class1")
Response.Write(CType(t.InvokeMember("s", BindingFlags.DeclaredOnly Or BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, obj, Nothing), String))
End Sub
End Class
End Namespace



パフォーマンスの問題もありますし、決してお勧めできるものではありませんけど。あくまで参考、ということで。
なかむら
ベテラン
会議室デビュー日: 2001/10/22
投稿数: 67
投稿日時: 2003-06-18 09:34
返事が遅くなってしまってすみません。

NothingButXMLInfoSetさん、GUNNMさん、ありがとうございました。
結論として、クラスファイルを@Assemblyディレクティブで読み込ませても参照はできないということですよね。
動的コンパイルで他のクラスを参照したい場合、同じWebForm.aspx.vbのソース内に記述してやれば参照可能ということで。
さすがにちょっと使い勝手悪いですが、仕方ないですね。

それにしてもNothingButXMLInfoSetさんのPage_Load時のコンパイルはすごいですね。
やはりパフォーマンス的に問題ありそうですが、こういう方法もあるとは・・・勉強になりました。

どうもありがとうございました。
1

スキルアップ/キャリアアップ(JOB@IT)