Dynamic JavaScript returned by webapi

2019-07-15 22:25发布

I am using requirejs to load JavaScript for my page. I have a webApi route that dynamically reads from a file and returns JSON using the Newtonsoft JObject. On the client side I then take the result and assign it to a local JavaScript variable.

define(['jquery'], function ($) {

function dynoFile() {
    $.get('/api/resources/dynofile', function (results) {
        myNamespace.dynoFile = results;
    });
}

return new dynoFile(); });

This example does work, however it causes problems with other JavaScript files that expect myNamespace.dynoFile to exist. Since this file loaded just fine, the other files don't wait around for the $.get to complete.

Is it possible to have a web api method return just JavaScript and have the browser recognize it as JavaScript and not just text? I've attempted to set response headers in the web api and a variety of ways to return the script that is generated.

Is this possible?

UPDATE:

To go into a little more detail, I am using my Web API to process my resources file and return JSON to the client as it is a single page app. I was hoping to just return JavaScript from my Web API that I could use RequireJS to load. I have it working now as JSON and thought I would share what I have.

Here is my WebApi method that reads a resource file and returns it as JSON:

public JObject Get()
{
    var data = new JObject();

    var type = typeof(Translations);
    var properties = type.GetProperties();

    foreach (var property in properties)
    {
        if (property.Name != "ResourceManager" && property.Name != "Culture")
        {
            data.Add( property.Name, property.GetValue(type, null).ToString());
        }
    }

    HttpContext.Current.Response.Headers.Add("Content-Type", "application/json");

    return data;
}

Here is my translations.js file:

define(['jquery', 'underscore'], function ($) {

    function translations() {
    }

    _.extend(translations.prototype, {
        target: '/api/resources/translations',

        getTranslations: function () {
            return $.ajax({
                url: 'api/resources/translations',
                type: 'GET',
                dataType: 'json'
            });
        }
    });

    return (translations);
});

Since several of my other files depend on the the translations existing, I needed to nest 2 RequireJS statements in my main.js:

requirejs(['application/translations', 'whatever other resources that can load that don't depend on translations'], function () {
    var trans = new translations();

    trans.getTranslations()
        .done(function (result) {
            // set translations into a variable, we chose it to be part of the global namespace
            window.Translations = result;

            // load remaining dependencies that require translations to exist
            requirejs(['myotherjsfiles', 'blahblah', function () {
                // you get the idea...
            });
        });
});

This allows my translation to load first (with any non dependent files such as bootstrap, jquery, etc.) and then load all my dependent JavaScript files after. I also tested this against the RequireJs optimization method and it's able to resolve the nested requires. Hopefully this helps someone else out with how to get translations down to the client and/or how to use RequireJS to load dynamic modules.

If anyone knows how to get WebApi to return JavaScript, I would love to hear about it!

Cheers!

1条回答
叼着烟拽天下
2楼-- · 2019-07-15 22:48

You want this question: Is there a way to force ASP.NET Web API to return plain text?

You don't need to create a PlainTextFormatter (I think the only benefit is automatic capturing when text/plain is requested?), you just need a helper method:

    /// <summary>
    /// Generate raw content from the given string output.
    /// <para>See https://stackoverflow.com/a/13028027/1037948 and https://stackoverflow.com/a/11582207/1037948 </para>
    /// </summary>
    /// <param name="responseBody"></param>
    /// <param name="mediaType"></param>
    /// <returns></returns>
    private HttpResponseMessage getRawResponse(string responseBody, string mediaType = "text/plain") {

        var response = Request.CreateResponse(HttpStatusCode.OK);
        response.Content = new StringContent(responseBody, Encoding.UTF8, mediaType);
        return response;
    }

Then for any GetSomething method(s), you write:

    public object GetMySomething1() {

        return getRawResponse(string.Format(@"window.SomeValue = {{{0}}}",
                            string.Join(",",
                                        Enum.GetValues(typeof(RandomEnum)).Cast<RandomEnum>().Select(o => string.Format("{0}:\"{1}\"", o, o)))
            ));
    }

Which results in a request to /myapicontroller/getmysomething1/ (assuming your route is set up to allow actions) returning:

window.SomeValue = {RandomValue1:"RandomValue1",RandomValue2:"RandomValue2",...}
查看更多
登录 后发表回答