自问没有得罪过各位大虾呀,为什么都不理我呢?问题:COM+和网站设计 ( 积分: 300 )

  • 主题发起人 主题发起人 Shuzi
  • 开始时间 开始时间
S

Shuzi

Unregistered / Unconfirmed
GUEST, unregistred user!
在我们实施的一个项目中,为了与业务系统紧密结合,按下面结构架设了一个网站,
目前已经投入使用,但有一些问题,请有经验的朋友指点一二。
1. 业务系统维护网站的相关数据及网站用户权限等,我们称之为网站发布;
2. 创建一个称之为Web Server的COM+组件,主要是根据业务系统发布的页面数据提供HTML;
3. 一个ASP组件(COM+),调用Web Server,引导网站。
其中第3项原来用ISAPI直接与Web Server连接,但很不稳定,并且ISAPI不好控制,所以换成
了ASP。
现在我的问题是:
1. 一般的页面基本上没有什么问题,但数据提交页面,特别是用户较多时(也就一、二十个
并发用户)经常报类似下面的错误(不是一定报错,是时不时的):
Access violation at address 00D2442E in module 'borlndmm.dll'. Write of address CAEAB1C0

2. 一般的数据采集页中,因为涉及大量的编码表需要供用户选择,所以采用了HTC技术单独提取编码
数据,这样对IIS而言是否是并发用户更多呢?
3. 关于COM+组件的那几种线程模型,我实在搞不明白,象我这种情况到底该用什么模型?
4. COM+组件的配置有没有什么比较详细的书?
5. ...

网站地址:
http://rsc.xjmu.edu.cn
 
在我们实施的一个项目中,为了与业务系统紧密结合,按下面结构架设了一个网站,
目前已经投入使用,但有一些问题,请有经验的朋友指点一二。
1. 业务系统维护网站的相关数据及网站用户权限等,我们称之为网站发布;
2. 创建一个称之为Web Server的COM+组件,主要是根据业务系统发布的页面数据提供HTML;
3. 一个ASP组件(COM+),调用Web Server,引导网站。
其中第3项原来用ISAPI直接与Web Server连接,但很不稳定,并且ISAPI不好控制,所以换成
了ASP。
现在我的问题是:
1. 一般的页面基本上没有什么问题,但数据提交页面,特别是用户较多时(也就一、二十个
并发用户)经常报类似下面的错误(不是一定报错,是时不时的):
Access violation at address 00D2442E in module 'borlndmm.dll'. Write of address CAEAB1C0

2. 一般的数据采集页中,因为涉及大量的编码表需要供用户选择,所以采用了HTC技术单独提取编码
数据,这样对IIS而言是否是并发用户更多呢?
3. 关于COM+组件的那几种线程模型,我实在搞不明白,象我这种情况到底该用什么模型?
4. COM+组件的配置有没有什么比较详细的书?
5. ...

网站地址:
http://rsc.xjmu.edu.cn
 
看看李维的MTS/COM+多层分布式开发,线程模型介绍的很清楚
COM+组件的配置也有。
 
谢谢楼上,那本书我有
线程模型本身并不难理解,我困惑的是什么情况下该用什么模型
 
注意!! 打劫的来了!! 快给老子分!! 快!!
 
用什么模型有区别吗
 
现在的关键是要找出第一个问题
 
关于你的第一个问题,有可能的原因是:
1.写COM+时访问了未创建的对象;或者你的逻辑处理比较复杂,在某处调用被释放了的对象。
2.ASP中创建不能被直接创建的COM+接口对象,比如像有明细功能模块(例如订单ComOrder),订单明细接口对象ComOrderDetail是只能由ComOrder调用的COM+接口,这时如果你在ASP代码中创建ComOrderDetail并开始调用它的接口时,会产生你描述的错误。
而这种错误的产生仍然是在接口中访问了未创建的业务对象。
 
谢谢gondsoft的回答
"写COM+时访问了未创建的对象",这个应该不会,如果是这样应该每次都出错的,我现在是用户多的时候才出错。至于“在某处调用被释放了的对象”倒有可能,但我找到了好几天也没找出来。根据LOG记录出来的情况分析,感觉特奇怪,似乎是在方法执行过程中,前几条语句都是好好的,到中间的一条调用对象过程的语句出错,但又没有进入到那个过程里面去,就好象是在执行过程中对象本身被别的线程释放了似的。但一个组件实例正在干活时,别的线程应该进不来呀。
不好意思,你说的第二点,我没看太明白,能否请你说详细点?其实我的ASP组件倒是很简单,就发布一个方法供.ASP文件调用,内部将Request的相关域值传给Web Server组件,然后调其生成网页HTML的函数,最后回给浏览器。
 
如果有出错的相关代码,可能更好分析一点。
 
to gondsoft:
代码比较复杂,牵涉到一些底层的包,我摘一些请你分析一下
1.ASP组件,一个单独的COM+组件DLL
TZuoerWebAspStarter = class(TASPObject, IZuoerWebAspStarter)
private
FRequest: TASPRequest;
FHtmlProvider:TZuoerHtmlProvider;
procedure SetReqParams;
...
protected
procedure OnEndPage; safecall;
procedure OnStartPage(const AScriptingContext: IUnknown); safecall;
procedure StartPage; safecall;
...
end
....
implementation

procedure TZuoerWebAspStarter.Initialize;
begin
inherited Initialize;
FHtmlProvider:=TZuoerHtmlProvider.Create(nil);
FHtmlProvider.OnLogin:=SaveUserInfo;
FHtmlProvider.OnGetUploadFiles:=GetUploadFiles;
FHtmlProvider.OnUploadToStream:=UploadFile;
end;

procedure TZuoerWebAspStarter.StartPage;
begin
try
//FHtmlProvider.ConnectKind:=ckNewInstance;
FHtmlProvider.Connect;
try
//SetReqParams(FHtmlProvider.ReqParams);
SetReqParams;
Response.Write(FHtmlProvider.PageDoc);
finally
FHtmlProvider.Disconnect;
end;
except
on E:Exception do Response.Write(E.Message);
end;
end;
procedure TZuoerWebAspStarter.SetReqParams;
var
I:Integer;
Param:string;
begin
FHtmlProvider.SetParam(mnRqHost,WebRequest.Host);
FHtmlProvider.SetParam(mnRqUrl,WebRequest.URL);
FHtmlProvider.SetParam(mnRqMethod,WebRequest.Method);
FHtmlProvider.SetParam(mnRqRemoteAddr,WebRequest.RemoteAddr);
FHtmlProvider.SetParam(mnRqRemoteHost,WebRequest.RemoteHost);
FHtmlProvider.SetParam(mnRqQuery,WebRequest.Query);
FHtmlProvider.SetParam(mnRqProtetcolVersion,WebRequest.ProtocolVersion);
FHtmlProvider.SetParam(mnRqScriptName,WebRequest.ScriptName);
FHtmlProvider.SetParam(mnRqServerPort,IntToStr(WebRequest.ServerPort));
FHtmlProvider.SetParam('RQ_PathInfo',WebRequest.PathInfo);
for I:=0 to WebRequest.QueryFields.Count-1 do
with WebRequest.QueryFields do
FHtmlProvider.SetParam(Names,Values[Names]);
for I:=0 to WebRequest.ContentFields.Count-1 do
with WebRequest.ContentFields do
FHtmlProvider.SetParam(Names,Values[Names]);

//Cookie中的项加'RQ_'前缀与QueryString、Form区别
Param:=GetCookieValue(mnUserName); //用户名
FHtmlProvider.SetParam('RQ_'+mnUserName,Param);
Param:=GetCookieValue(mnSessionId); //SessionId
FHtmlProvider.SetParam('RQ_'+mnSessionId,Param);
Param:=WebRequest.CookieFields.Values[mnSessionId]; //Session生数据
FHtmlProvider.SetParam('RQ_'+mnSession,Param);
//其他的Cookie值
for I:=0 to WebRequest.CookieFields.Count-1 do
with WebRequest.CookieFields do
if not (SameText(Names,mnUserName) or
SameText(Names,mnSessionId)) then
FHtmlProvider.SetParam('RQ_'+Names,Values[Names]);

end;
....
网站的引导页ASP创建该对象,调用 StartPage 取得网页内容。
StartPage 主要是建立与另一个提供页面的COM+组件的连接,设置相关请求参数,取回HTML,即 FHtmlProvider.PageDoc
 
2.页面HTML提供组件
TZuoerHtmlProvider = class(TMtsAutoObject, IConnectionPointContainer, IZuoerHtmlProvider)
...
procedure Initialize; override;
...
function PageDoc: WideString; safecall;
..
implementation
....
procedure TZuoerHtmlProvider.Initialize;
begin
try
inherited Initialize;
FConnectionPoints := TConnectionPoints.Create(Self);
if AutoFactory.EventTypeInfo <> nil then
FConnectionPoint := FConnectionPoints.CreateConnectionPoint(
AutoFactory.EventIID, ckSingle, EventConnect)
else FConnectionPoint := nil;
if not SysInitialized then
begin
ReadRegistry; //win2003中 ZRNoReg.Pas的初始化似乎没有执行
WebAppInitiale;
end;
if not Assigned(FResProvider) then
begin
FResProvider:=TWebResProvider.Create(nil);
FResProvider.RunLogs.Add(Format('Created by %d',[Integer(Self)]));
FResProvider.OnLogin:=LoginOkEvent;
FResProvider.OnGetUploadFiles:=GetUploadFilesEvent;
FResProvider.OnUploadFile:=UploadFileEvent;
FResProvider.Macros.MacroText['COM Instance']:=Format('%d',[Integer(Self)]);
FResProvider.Macros.MacroText['HInstance']:=Format('%d',[HInstance]);
end;
FResProvider.RunLogs.Add(Format('%d Initialized.',[Integer(Self)]));
except
on E:Exception do
raise Exception.Create('Initialize error.'^M^J+E.Message);
end;
end;

destructor TZuoerHtmlProvider.Destroy;
begin
if Assigned(FResProvider) then
begin
FResProvider.RunLogs.Add(Format('Destroy by %d',[Integer(Self)]));
if FResProvider.Tag=-1 then
AppendLog('运行记录'^M^J+FResProvider.RunLogs.Text);
FreeAndNil(FResProvider);
end;
Inherited Destroy;
end;

function TZuoerHtmlProvider.PageDoc: WideString;
begin
try
Result:=FResProvider.Content;
SetComplete;
except
SetAbort;
raise;
end;
end;
....
initialization
begin
TAutoObjectFactory.Create(ComServer, TZuoerHtmlProvider, Class_ZuoerHtmlProvider,
ciMultiInstance, tmNeutral); //tmNeutral有问题吗?
end;

FResProvider是在另一个BPL中的对象,主要负责访问数据库(ORACLE),生成HTML
 
3.页面HTML生成对象 FResProvider
主要出错的地方:

function TCustomWebResProvider.TakeContent: string;
var
iPos:Integer;
Tick:Cardinal;
HTMLs:string;
begin
IPos:=0;
try
AppendLog('?'+FMacros.MacroText[mnRqQuery],1); IPos:=1;
Tick:=GetTickCount; IPos:=2;
BeforeGenPage;IPos:=3; //到这儿都是好的
try
case PageMode of //可能这儿出错
pmLogin:
begin
DoLogin;
HTMLs:=GetPageDoc(nil);
HTMLs:=AddScripts(HTMLs);
HTMLs:=Format(SPageHeadFlag,[GetTickCount-Tick])+HTMLs;
end;
pmLogout:
begin
DoLogout;
HTMLs:=GetPageDoc(nil);
HTMLs:=AddScripts(HTMLs);
HTMLs:=Format(SPageHeadFlag,[GetTickCount-Tick])+HTMLs;
end;
pmAsyn:
begin
try
HTMLs:=GetPageDoc(nil);
except
on E:Exception do
begin
FTag:=-1;
HTMLs:='请求列表数据失败';
AppendLog(HTMLs+':'^M^J+E.Message,0);
end;
end;
HTMLs:=JSEscape(HTMLs);
end;
else
HTMLs:=GetPageDoc(nil); IPos:=4; //可能这儿出错?
HTMLs:=AddScripts(HTMLs); IPos:=5;
HTMLs:=Format(SPageHeadFlag,[GetTickCount-Tick])+HTMLs;IPos:=6;
end;
Result:=HTMLs; IPos:=7;
finally
AfterGenPage(Result);
end;
except
on E:Exception do
begin
FTag:=-1;
E.Message:=E.Message+'('+IntToStr(iPos)+')'; //第一次错误时,IPos大多是3
Result:=GetErrorHtml(E);
end;
end;
end;

第一次错误时,IPos大多是3,后面的错就不一定了

------------------------------
麻烦你
 
TZuoerHtmlProvider = class(TMtsAutoObject, IConnectionPointContainer, IZuoerHtmlProvider)
...
procedure Initialize; override;
//加上
procedure FreeInstance; override;


procedure TZuoerHtmlProvider.FreeInstance;
begin
if Assigned(FResProvider) then
FreeAndNil(FResProvider);
//也可以把Destroy过程里的代码放到这里来,Destroy不用重载。
end;
 
请问组件的线程模型一般选什么?tmNeutral还是tmApartment, 两个组件必须是一样的线程模型吗?
 
有时候,Windows的事件日志会有下面的错误信息,请各位看看能不能发现什么?

系统调用了一个自定义组件,此组件已失败并产生了一个异常。这说明自定义组件有问题。请通知此组件的开发人员并提供他们下列信息。
组件进程 ID: ZuoerHtmlProvider Object
方法名称: IObjectControl::Deactivate()
服务器应用程序 ID: {3B0D940D-D63C-486B-8389-76BF8379565C}
服务器应用程序实例 ID:
{545C294D-96EE-4092-982D-70F56D25766C}
服务器应用程序名: Zuoer Web Application Server
此错误的严重性已导致进程终止。
异常: C0000005
地址: 0x00AE460B
调用堆栈:
borlndmm!@Borlndmm@SysFreeMem$qqrpv + 0x117
borlndmm!ReallocMemory + 0xddd
rtl70!@System@@FreeMem$qqrpv + 0xb
rtl70!@Classes@TStrings@GetValue$qqrx17System@AnsiString + 0x2d
ZR30_PUB_D7!@Zrclass@TStringList@GetInt$qqr17System@AnsiStringi + 0x37
ZR30_PUB_D7!@Zrclass@TStringList@GetIntValue$qqr17System@AnsiString + 0x2c
ZR30_MDS_D7!@Zrwebclass@TCustomWebResProvider@AppendLog$qqrx17System@AnsiStringi + 0x3e
ZRWebAppSvc!DllUnregisterServer + 0x2579
ZRWebAppSvc!DllUnregisterServer + 0x130e
COMSVCS!RegisterComEvents + 0x4f141
COMSVCS!RegisterComEvents + 0x4fa08
COMSVCS!RegisterComEvents + 0x50e04
ole32!OleSetMenuDescriptor + 0xceb3
ole32!OleSetMenuDescriptor + 0xf726
+ 0x80a48
+ 0x2f005f6


有关更多信息,请参阅在 http://go.microsoft.com/fwlink/events.asp 的帮助和支持中心。
 
好像是什么东西没释放的缘故,Thread模式就用tmApartment就行了
 
现在就是tmApartment线程模型
因为生成HTML的对象是在一个BPL中,其中用到了一些公共变量,所以我怀疑是线程安全方便的问题,但不知怎栏避免。
 
只能帮楼主吆喝一下。
 
后退
顶部