Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing Callback Exception #28

Open
gbd77rc opened this issue Mar 5, 2014 · 5 comments
Open

Missing Callback Exception #28

gbd77rc opened this issue Mar 5, 2014 · 5 comments

Comments

@gbd77rc
Copy link

gbd77rc commented Mar 5, 2014

Hi,

If I have an ODATA (EntitySetController) endpoint that I want to switch between JSONP and JSON via ACCEPT header (application/json-p or application/odata), this formatter will throw an exception complaining about a missing callback parameter.

The issue happens in the GetPerRequestFormatterInstance method. It seems that the content negotiation is happening and this method get called before the check for supported media types. I could be wrong here, but from debugging the source code this seems to be what is happening. I am using Visual Studio 2013, with ODATA 5.6.1 assemblies.

For my own issue I have modified the code in three places.

In the GetPerRequestFormatterInstance

        string callback;
        // Check if we do have callback and therefore really what jsonp
        if (IsJsonpRequest(request, _callbackQueryParameter, out callback))
        {
            return new JsonpMediaTypeFormatter(request, callback, _jsonMediaTypeFormatter, _callbackQueryParameter);
        }
        else
        {
            // Check if we really want ODATA and therefore need to continue
            // and test the supported media types.
            if (type.GetInterfaces().Contains(typeof(IQueryable)))
            {
                return new JsonpMediaTypeFormatter(request, _jsonMediaTypeFormatter, _callbackQueryParameter);
            }
        }

In the CanWriteType method I check if we can write the type back, if it is a ODATA request and the ACCEPT header is "application/odata" then just return false.

        var accepttype = false;
        //Get the accept header.
        if ( _request != null )
        {
            accepttype = _request.Headers.Accept.Any(a => a.MediaType.ToLower() == "application/odata");
        }

        // Check for ODATA 
        if ( type.GetInterfaces().Contains(typeof(IQueryable))
             && accepttype )
        {
            return false;
        }

Added a new constructor so we can have a default value for the callback, but to be honest I don't think it is required.

    private JsonpMediaTypeFormatter(HttpRequestMessage request, MediaTypeFormatter jsonMediaTypeFormatter, string callbackQueryParameter)
        : this(jsonMediaTypeFormatter, callbackQueryParameter)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        _request = request;
        _callback = "foobar";
    }

I have not forked or submitted these changes as I don't think they will be suitable for everyone. I just wanted you to know that someone else may run into this issue if they have a mix of standard webapi endpoints and EntitySetController endpoints in their service and need to have JSONP as well. Normally I use CORS but I have been told I need to support IE 8 now :(, hence the reason for JSONP.

Regards

Richard...

@panesofglass
Copy link
Member

Thanks for submitting the issue.

Can you move the OData formatter before the JSONP formatter? Formatter selection happens when you create your HttpContent, which may be done by Web API if you don't explicitly return an HttpResponseMessage. This makes it really hard for cases where you may want to change the returned media type.

Perhaps the right thing to do here is to have CanWriteType return false whenever the callback is missing. Do you think that might work? The Accept header may not be used in every case.

@gbd77rc
Copy link
Author

gbd77rc commented Mar 5, 2014

Hi Ryan,

Thanks for the reply. That idea about the CanWriteType may work I will give it a try later today hopefully. I believe the EntitySetController stuff dynamically adds ODataMediaTypeFormatter or whatever it is called, so I have not found a place to add the JSONP formatter.

Regards

Richard….

From: Ryan Riley [mailto:[email protected]]
Sent: 05 March 2014 14:16
To: WebApiContrib/WebApiContrib.Formatting.Jsonp
Cc: Richard Clarke
Subject: Re: [WebApiContrib.Formatting.Jsonp] Missing Callback Exception (#28)

Thanks for submitting the issue.

Can you move the OData formatter before the JSONP formatter? Formatter selection happens when you create your HttpContent, which may be done by Web API if you don't explicitly return an HttpResponseMessage. This makes it really hard for cases where you may want to change the returned media type.

Perhaps the right thing to do here is to have CanWriteType return false whenever the callback is missing. Do you think that might work? The Accept header may not be used in every case.


Reply to this email directly or view it on GitHub #28 (comment) . https://github.com/notifications/beacon/2116050__eyJzY29wZSI6Ik5ld3NpZXM6QmVhY29uIiwiZXhwaXJlcyI6MTcwOTY0ODE3MywiZGF0YSI6eyJpZCI6MjY5ODY4NDV9fQ==--e4fd5fe4de36b8fca77fec90af06c05677db846b.gif

@tangrl
Copy link

tangrl commented Jan 27, 2015

I just added OData 4 endpoints to my OData 3 web service. It now always picks up JsonpMediaTypeFormatter for any OData request, no matter what I do. I tried the code above and it will break the OData json format. Is there any way for OData requests not picking up the JsonpMediaTypeFormatter?

Richard

@panesofglass
Copy link
Member

Make sure the OData JSON formatter is registered before the JSON-P formatter. If that doesn't fix it; I'm not sure. I don't use OData. I also don't use JSON-P; I use CORS. If you can figure out the problem and send a Pull Request, I'll be happy to review and merge it.

@tangrl
Copy link

tangrl commented Feb 3, 2015

I made the change to the following two functions and it seems working fine. I'm not sure what kind of side-effect it will cause.

    private JsonpMediaTypeFormatter(HttpRequestMessage request, string callback,
        MediaTypeFormatter jsonMediaTypeFormatter, string callbackQueryParameter)
        : this(jsonMediaTypeFormatter, callbackQueryParameter)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        //if (callback == null) //TODO - Commented out to avoid exception for OData V4 request. Better solution?
        //{
        //    throw new ArgumentNullException("callback");
        //}

        _request = request;
        _callback = callback;
    }

    public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request,
        MediaTypeHeaderValue mediaType)
    {
        if (type == null)
        {
            throw new ArgumentNullException("type");
        }

        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        //string callback; //TODO - Commented out to avoid exception for OData V4 request. Better solution?
        //if (IsJsonpRequest(request, _callbackQueryParameter, out callback))
        //{
        //    return new JsonpMediaTypeFormatter(request, callback, _jsonMediaTypeFormatter, _callbackQueryParameter);
        //}
        //throw new InvalidOperationException("NoCallback");

        string callback;
        IsJsonpRequest(request, _callbackQueryParameter, out callback);
        return new JsonpMediaTypeFormatter(request, callback, _jsonMediaTypeFormatter, _callbackQueryParameter);
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants