Hello All,
I am using an IHttpAsyncHandler class to intercept HTTP Requests and forward
them to a system which processes the Request and returns the Result.
I use .NET Remoting to connect the IHttpAsyncHandler object to the System
and transfer the Request and Result between the two.
This works fine for quite a while, and then I start to get the following
error.
"This remoting proxy has no channel sink which means either the server has
no registered server channels that are listening, or this application has no
suitable client channel to talk to the server"
At this point I can't access the IAsyncHandler objects and the Server has to
be restarted.
As a note, the IHttpAsynHandler objects are managed in a pool by IIS.
In order to maintain the HTTPContext for the request, the system caches the
IHttpAsyncHandler Proxy until the request is processed, and then returns the
Result via this proxy instance. It is at this time that I get the
exception.
I am attaching some sample code for the client and server.
Thanks to all in advance
Mike Grishaber
mg********@cp.org
The following is code from the Client. Note that this runs under IIS as an
asp.net IHttpAsyncHandler.
The InitializeChannel method creates the .NET Remoting connection to the
server called m_RequestManager.
/// <summary>
/// This method will register tcp channel and connect to RequestManager.
/// </summary>
protected override void InitializeChannel()
{
//Register channel if not already registered
//create TcpChannel with port set to 0. Giving it as 0 instead means
//that the framework should look for a free port and use this.
m_Channel = new TcpChannel(0);
//Register Channel
ChannelServices.RegisterChannel(m_Channel);
//set registered flag to true
m_ChannelIsRegistered = true;
m_RequestManager = null;
m_RequestManager =
(RequestManager)Activator.GetObject(typeof(Request Manager),"tcp://" + HOST +
":" + PORT + "/" + URI);
}
The next method BeginProcessRequest() is called by IIS when the HTTPRequest
is received. The IHttpAsyncHandler object will connect to the
RequestManager server and send the request. An IAsyncResult object is
returned to IIS so that we can retieve the IHttpAsyncHandler from the pool
when we need it.
/// <summary>
/// This method is called asynchronously by ASP.Net. In this method we
create a
/// Async object which allows us to keep track of state between this method
and
/// EndProcessRequest. After BuildRequest is called the Async object is
returned
/// to IIS. EndProcessRequest will not be invoked intill
m_Async.SetCompleted() is
/// called.
/// </summary>
/// <param name="context">Http context object.</param>
/// <param name="cb">Call back method</param>
/// <param name="extraData">asyncState</param>
/// <returns>Async object</returns>
public IAsyncResult BeginProcessRequest(HttpContext context,
System.AsyncCallback cb, object extraData)
{
//create Async class to return to IIS
m_Async = new Async(cb,extraData);
//get context to use output stream
m_Async.context = context;
//create request object
m_Request = new Cp.Util.Request();
//set request paramaters
m_Request.Parameters = new
NameValueCollection(m_Async.context.Request.Params );
//set Request ID using IDGenerator class. IDGenerator uses .Net GIUD Class.
IDGenerator RequestGiud = IDGenerator.GetInstance();
//set request id with unique id using .Net GUID class
m_Request.ID = RequestGiud.GetID("Pre","Suff");
//pass request object and (this)sink to requestmanager
m_RequestManager.NewRequest(m_Request,this);
//return object to IIS
return m_Async;
}
The next method EndProcessRequest() is called when processing is completed
and the Server has sent back the Result. The IAsyncResult object is invoked
and IIS will call EndProcessRequest().
/// <summary>
/// Called by IIS by when request is ready to stream content to client. IIS
passes
/// the Async as parameter. From here we can get the correct http context of
the
/// clients request and send the response stream back.
/// </summary>
/// <param name="result">Async object</param>
public void EndProcessRequest(IAsyncResult result)
{
//get Async object from IIS
Async async = (Async)result;
//write result to client
async.context.Response.StatusCode = m_StatusCode;
async.context.Response.Write(m_ResponseString);
this.Close();
}
The following is the Server side code....
The next method RegisterChannel() sets up the .NETRemoting server.
/// <summary>
/// This method will registar our TCP Server Channel.
/// </summary>
protected virtual void RegisterChannel()
{
//create binary server formatter
System.Runtime.Remoting.Channels.BinaryServerForma tterSinkProvider provider
= new System.Runtime.Remoting.Channels.BinaryServerForma tterSinkProvider();
//set formatter TypeFilterLevel to full to allow passing of delegates and
object references over Remoting boundaries
provider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilter Level.Full;
//create tcp server channel
m_Channel = new TcpServerChannel("RequestManagerChannel",m_Port,pr ovider);
ChannelServices.RegisterChannel(m_Channel); //registar channel
}
The next method is the NewRequest() method which is exposed as a remoting
interface for the client to call.
/// <summary>
/// This method will receive new RequestSink from sink classes.
/// Request object and ID will be mapped by MapRequest method. Request
object will
/// be sent to transaction sub-system.
/// </summary>
/// <param name="Sink">RequestSink</param>
public void NewRequest(Cp.Util.Request InRequest,RequestSink Sink)
{
//map Request
m_ResultRouter.MapRequest(InRequest.ID, Sink);
//send request to outbox
m_TransactionOutBox.SendObject(InRequest);
}
The next method is the Run() method which receives the Result back for the
request, retrieves the IHttpAsyncHandler proxy instance and sends the Result
to it. It is at this point that the exception occurs.
public void Run()
{
//begin send stream process on sink
try
{
if(Sink != null)
{
Sink.SendStream(NewResult.ReturnObject.ToString(),
NewResult.ProfileID.ToString(), NewResult.LanguageID.ToString(),
NewResult.IsSuccess);
Sink = null;
}
}
catch(Exception e)
{
LogEntry entry = new LogEntry(LogEntry.WARNING,
"Exception Closing HTTPSink.\r\n" + e.Message,
"Cp.Request","RequestManager.Run");
if(m_Logger!= null)
{
m_Logger.LogMessage(entry, true);
}
}
//unmap sink in ResultRouter
m_ResultRouter.UnmapRequest(NewResult.ID);
}