views:

218

answers:

0

Hi --

I'm trying to submit some Json data to an ASP.NET MVC controller from a WPF app. I wrote my client-side code based on a couple of samples from MSDN using the WebRequest object and BeginGetResponse. This worked fine when I was just sending a GET request. It hit my ASP.NET MVC controller just fine and brought back some Json data. But when I try to switch to using a POST verb, it isn't working. I know the controller is wired up okay, because I can hit it from a web browser typing in the URL manually. I'm pretty sure I must be making a mistake in how I set up the POST.

I'm including the code below up to the point where I issue the BeginGetResponse. (I don't include my async BeginGetResponse callbacks, because the request times out and never hits the callback. If someone can tell me what I am doing wrong, I would be greatly appreciative.

On the client side here's the setup code (following it below I have my asp.net mvc controller code). I call the WebRequest_BeginGetResponse.GetResponse method in the following code from a WPF button click handler, passing in my target url, which I am 100% certain is the correct one:

public class RequestState
{
    // This class stores the state of the request.
    const int BUFFER_SIZE = 1024;
    public StringBuilder requestData;
    public byte[] bufferRead;
    public WebRequest request;
    public WebResponse response;
    public Stream responseStream;
    public RequestState()
    {
        bufferRead = new byte[BUFFER_SIZE];
        requestData = new StringBuilder("");
        request = null;
        responseStream = null;
    }
}

class WebRequest_BeginGetResponse
{
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    const int BUFFER_SIZE = 1024;
    Window1 ui;
    delegate void PlainMethod();
    StringBuilder theResults;
    const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout

    // Abort the request if the timer fires.
    private static void TimeoutCallback(object state, bool timedOut)
    {
        if (timedOut)
        {
            HttpWebRequest request = state as HttpWebRequest;
            if (request != null)
            {
                request.Abort();
            }
        }
    }

    public WebRequest_BeginGetResponse(Window1 userInterface)
    {
        ui = userInterface;
        theResults = new StringBuilder();
    }

    public void GetResponse(string url)
    {
        // Create a new webrequest to the mentioned URL.   
        WebRequest myWebRequest = WebRequest.Create(url);
        myWebRequest.Method = "POST";
        myWebRequest.ContentType = "application/json";
        Stream requestStream = myWebRequest.GetRequestStream();

        DataContractJsonSerializer theSerializer = new DataContractJsonSerializer(typeof(List<string>));
        List<string> theAddressList = new List<string>();
        theAddressList.Add("[email protected]");
        theAddressList.Add("[email protected]");
        theAddressList.Add("[email protected]");
        theAddressList.Add("[email protected]");
        theAddressList.Add("[email protected]");

        theSerializer.WriteObject(requestStream, theAddressList);
        // myWebRequest.ContentLength = requestStream.Length;

        // Create a new instance of the RequestState.
        RequestState myRequestState = new RequestState();
        // The 'WebRequest' object is associated to the 'RequestState' object.
        myRequestState.request = myWebRequest;
        // Start the Asynchronous call for response.
        IAsyncResult asyncResult = (IAsyncResult)myWebRequest.BeginGetResponse(
            new AsyncCallback(RespCallback), myRequestState);
        ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myWebRequest, DefaultTimeout, true);

        // The response came in the allowed time. The work processing will happen in the 
        allDone.WaitOne();
        myRequestState.response.Close();
        ui.Dispatcher.Invoke(DispatcherPriority.Normal, (PlainMethod)delegate
        {
            ui.textBlock1.Text = theResults.ToString();
        });
        // Release the WebResponse resource.
    }

Here's the ASP.NET MVC controller code:

public class NotifyEmailController : Controller
{
    //
    // GET: /NotifyEmail/

    [JsonFilter(Param="theSendRequest",RootType=typeof(NotifyEmailAddressRequest))]
    // [AcceptVerbs(HttpVerbs.Post)]
    public NotifyEmailAddressActionResult ToAddress(NotifyEmailAddressRequest theSendRequest)
    {
        NotifyEmailAddressActionResult theResult = new NotifyEmailAddressActionResult();
        EmailSender theMailer = new EmailSender();
        theResult.Success = theMailer.SendMail();
        return theResult;
    }

    [JsonFilter(Param = "theSendRequest", RootType = typeof(NotifyEmailAddressListRequest))]
    // [AcceptVerbs(HttpVerbs.Post)]
    public NotifyEmailAddressListActionResult ToAddressList(NotifyEmailAddressListRequest theSendRequest)
    {
        List<string> theSubmittedList = theSendRequest.EmailList;

        return new NotifyEmailAddressListActionResult();
    }

}

}

The JsonFilter is a small ActionFilter that deserializes the json data into an object. It (and the controller) both get invoked when I submit a url manually from a web browser, but not when I use the client code posted above. It's code is this:

public class JsonFilter : ActionFilterAttribute
{
    public string Param { get; set; }    
    public Type RootType { get; set; }    
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    {        
        if ((filterContext.HttpContext.Request.ContentType ?? string.Empty).Contains("application/json")) 
        {    
            object o = new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);            
            filterContext.ActionParameters[Param] = o;        
        }
    }
}

Thanks for any help that anyone can provide.

Regards,

Mike