Pregunta

Actualmente estoy intentando modificar algunas funciones de HttpWebRequest, pero no puedo hacerlo por herencia porque HttpWebRequest no tiene constructores públicos (además del constructor de deserialización). ¿Hay una solución para hacer esto?

Mi objetivo es codificar algo como el ejemplo a continuación, pero los objetos de esta clase deben heredar las propiedades y métodos de HttpWebRequest:

using System;
using System.Net;
using System.Threading;

public class AsyncWebRequest:WebRequest
{
    private readonly AsyncCallback getResponseCallback;
    private readonly Uri uri;
    private volatile int RetriesLeft = 3;
    private volatile WebRequest request;

    public AsyncWebRequest(string uri, AsyncCallback getResponseCallback)
       :this(new Uri(uri), getResponseCallback)
    {
    }

    public AsyncWebRequest(Uri uri, AsyncCallback getResponseCallback):base()
    {
        this.uri = uri;
        this.getResponseCallback = getResponseCallback;
    }

    private IAsyncResult BeginGetResponse()
    {
        request = HttpWebRequest.CreateDefault(uri);
        ((HttpWebRequest)request).ReadWriteTimeout = Timeout;
        var result = request.BeginGetResponse(GetResponseCallback, null);
        ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
            GetResponseTimeout, null, Timeout, true);
        return result;
    }

    private void GetResponseTimeout(object state, bool timedOut)
    {
        if (timedOut)
        {
            Retry();
        }
    }

    private void Retry()
    {
        request.Abort();
        bool retry = false;
        lock (request)
        {
            if (RetriesLeft > 0)
            {
                Interlocked.Decrement(ref RetriesLeft);
                retry = true;
            }
        }
        if (retry)
        {
            BeginGetResponse();
        }
        else
        {
            getResponseCallback(null);
        }
    }

    private void GetResponseCallback(IAsyncResult AsyncResult)
    {
        try
        {
            getResponseCallback(AsyncResult);
        }
        catch(WebException webException)
        {
            Retry();
        }
    }
}
¿Fue útil?

Solución

A menos que pueda engañar al constructor de serialización para que haga su oferta, entonces no, no hay manera.

Los constructores de esa clase son internos, por lo que no tienes forma de llamarlos.

Otros consejos

No puede a través de la herencia de HttpWebRequest (si no desea llamar al constructor de serialización), pero puede hacerlo a través de la composición y la delegación, y a través de la herencia de WebRequest (no estoy seguro de si eso lo hará por usted, pero funcionalmente es bastante similar). WebRequest tiene un constructor predeterminado.

En este caso, entonces no puede tener la clase 'ser' un HttpWebRequest (como en una relación is-a), ya que no puede extenderse desde él, pero será 'be' un WebRequest, que debería ser suficiente .

Podría escribir una clase que hereda de WebRequest, que tenga un miembro de instancia de tipo WebRequest, crear una HttpWebRequest y asignarla a un miembro de instancia en el constructor del nuevo tipo y delegar todas las llamadas a esa referencia (una especie de patrón decorador ):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;

namespace ClassLibrary1
{
    public class MyHttpWebRequest : WebRequest
    {
        private WebRequest request;

        public MyHttpWebRequest(string uri)
        {
            request = HttpWebRequest.Create(uri);
        }

        public override WebResponse GetResponse()
        {
            // do your extras, or just delegate to get the original code, as long
            // as you still keep to expected behavior etc.
            return request.GetResponse();
        }

    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top