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

GET Api calls are re-directed #215

Closed
mmunchandersen opened this issue Jul 8, 2015 · 6 comments
Closed

GET Api calls are re-directed #215

mmunchandersen opened this issue Jul 8, 2015 · 6 comments

Comments

@mmunchandersen
Copy link
Contributor

I'm adding web api 2 methods to a asp.net mvc 5 project, however, when i18n is enabled, my GET method calls are being redirected to selected country. For example: http://xxx/api/v1/system/getappversion2 is redirected to http://xxx/en/v1/system/getappversion2

My POST methods are called correctly with or without i18n.

Must I somewhere exclude api from the i18n logic?

Two examples:
[Route("api/v1/system/getappversion"), HttpPost]
public HttpResponseMessage GetAppVersion()
{
const int appVersion = 1;
return Request.CreateResponse(HttpStatusCode.OK, new
{
AppVersion = appVersion
});
}

[Route("api/v1/system/getappversion2"), HttpGet]
public HttpResponseMessage GetAppVersion2()
{
const int appVersion = 1;
return Request.CreateResponse(HttpStatusCode.OK, new
{
AppVersion = appVersion
});
}

GetAppVersion (POST) work with or without i18n.
GetAppVersion2 (GET) only works without i18n. When i18n api/v1/system/getappversion2 is re-directed to en/v1/system/getappversion2

In Fiddler I get:

Terse summary
GET http://localhost:50708/api/v1/system/getappversion2
302 Redirect to /en/v1/system/getappversion2

GET http://localhost:50708/en/v1/system/getappversion2
404 Not Found (text/html)

Full summary
Result Protocol Host URL Body Caching Content-Type Process Comments Custom
1 302 HTTP localhost:50708 /api/v1/system/getappversion2 0 fiddler:9088
2 404 HTTP localhost:50708 /en/v1/system/getappversion2 3.204 private text/html; charset=utf-8 fiddler:9088

Headers only
GET http://localhost:50708/api/v1/system/getappversion2 HTTP/1.1
User-Agent: Fiddler
Host: localhost:50708

HTTP/1.1 302 Moved Temporarily
Location: /en/v1/system/getappversion2
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcTW9ydGVuXFByb2plY3RzXE5TQVxJblN0b3JlRXhjZWxsZW5jZVxzcmNcSW5TdG9yZUV4Y2VsbGVuY2UuV2ViXGFwaVx2MVxzeXN0ZW1cZ2V0YXBwdmVyc2lvbjI=?=
X-Powered-By: ASP.NET
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://.googleapis.com https://.gstatic.com https://www.google-analytics.com https://*.google.com; frame-ancestors 'self' https://www.google.com
Date: Wed, 08 Jul 2015 19:40:56 GMT
Content-Length: 0


GET http://localhost:50708/en/v1/system/getappversion2 HTTP/1.1
User-Agent: Fiddler
Host: localhost:50708

HTTP/1.1 404 Not Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcTW9ydGVuXFByb2plY3RzXE5TQVxJblN0b3JlRXhjZWxsZW5jZVxzcmNcSW5TdG9yZUV4Y2VsbGVuY2UuV2ViXHYxXHN5c3RlbVxnZXRhcHB2ZXJzaW9uMg==?=
X-Powered-By: ASP.NET
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' https://.googleapis.com https://.gstatic.com https://www.google-analytics.com https://*.google.com; frame-ancestors 'self' https://www.google.com
Date: Wed, 08 Jul 2015 19:40:56 GMT
Content-Length: 3204

@turquoiseowl
Copy link
Owner

@turquoiseowl
Copy link
Owner

Here is how you can exclude APIs from localization:

            i18n.UrlLocalizer.OutgoingUrlFilters += delegate(string url, Uri currentRequestUrl) {
                Uri uri;
                if (Uri.TryCreate(url, UriKind.Absolute, out uri)
                    || Uri.TryCreate(currentRequestUrl, url, out uri)) {
                    if (uri.LocalPath.IndexOf("/Api", StringComparison.OrdinalIgnoreCase) != -1) {
                        return false; }
                    if (uri.LocalPath.IndexOf("xdomain", StringComparison.OrdinalIgnoreCase) != -1) {
                        return false; }
                }
                return true;
            };

@mmunchandersen
Copy link
Contributor Author

update:

when I use:

i18n.UrlLocalizer.IncomingUrlFilters += delegate(Uri url)
{
    if (url.LocalPath.Contains("/api"))
        return false;
    return true;
};

instead of:

i18n.UrlLocalizer.OutgoingUrlFilters += delegate(string url, Uri currentRequestUrl)
{
    Uri uri;
    if (Uri.TryCreate(url, UriKind.Absolute, out uri)
        || Uri.TryCreate(currentRequestUrl, url, out uri))
    {
        if (uri.LocalPath.IndexOf("/api", StringComparison.OrdinalIgnoreCase) != -1)
            return false;
    }
    return true;
};

things to works as expected.

Hi Martin

thanks for your response. Still have the trouble, and hope you could give me a few pointers.

I just forked v2.1.4.0, build it, updated dll's in asp.net mvc project (tested it works), read the documentation and added your code suggestion (i18n.UrlLocalizer.OutgoingUrlFilters). However, I'm still getting the re-direct behaviour.

If I comment out the following in web.config the GET api method runs correctly:

<system.web><httpModules>
<add name="i18n.LocalizingModule" type="i18n.LocalizingModule, i18n" />

<system.webServer><modules>
<add name="i18n.LocalizingModule" type="i18n.LocalizingModule, i18n" />

In Global.asax.cs in protected void Application_Start() I have adding the following code:

i18n.UrlLocalizer.OutgoingUrlFilters += delegate(string url, Uri currentRequestUrl)
{
    Uri uri;
    if (Uri.TryCreate(url, UriKind.Absolute, out uri)
        || Uri.TryCreate(currentRequestUrl, url, out uri))
    {
        if (uri.LocalPath.IndexOf("/api", StringComparison.OrdinalIgnoreCase) != -1)
            return false;
    }
    return true;
};

The code (i18n.UrlLocalizer.OutgoingUrlFilters in Application_Start()) is never touched when calling the GET api method, and I'm still getting the re-direct behaviour:

Api methods:

public class SystemController : BaseApiController
{
    [Route("api/v1/system/GetApiVersion"), HttpPost]
    public HttpResponseMessage GetApiVersion()
    {
        return Request.CreateResponse(HttpStatusCode.OK, new
        {
            Version = Constants.ApiVersion
        });
    }

    [Route("api/v1/system/GetApiVersion2"), HttpGet]
    public HttpResponseMessage GetApiVersion2()
    {
        return Request.CreateResponse(HttpStatusCode.OK, new
        {
            Version = Constants.ApiVersion
        });
    }
}

Fiddler GET call (the one failing):

GET http://localhost:50708/api/v1/system/GetApiVersion2 HTTP/1.1
Host: localhost:50708

Fiddler response to GET call:

#   Result  Protocol    Host        URL             Body    Caching Content-Type    Process Comments    Custom  
8   302 HTTP        localhost:50708 /api/v1/system/GetApiVersion2   0                           fiddler:9088            
9   404 HTTP        localhost:50708 /en/v1/system/GetApiVersion2    3.204   private text/html; charset=utf-8        fiddler:9088            

Fiddler POST call (works):

POST http://localhost:50708/api/v1/system/GetApiVersion HTTP/1.1
Host: localhost:50708

Fiddler response to POST call:

#   Result  Protocol    Host    URL Body    Caching Content-Type    Process Comments    Custom  
42  200 HTTP    localhost:50708 /api/v1/system/GetApiVersion    13  no-cache; Expires: -1   application/json; charset=utf-8             

screenshot01592

the i18n web.config -> appSettings keys:

<add key="i18n.DirectoriesToScan" value="" />
<!--Rel to web.config file-->
<add key="i18n.WhiteList" value="*.cs;*.cshtml;*.sitemap;*.js" />
<add key="i18n.NuggetBeginToken" value="[#[" />
<add key="i18n.NuggetEndToken" value="]#]" />

@turquoiseowl
Copy link
Owner

Hmm, I can't see anything that you're doing wrong.

If I set a breakpoint in my OutgoingUrlFilter delegate then debug a request, here's my call stack when the BP get's hit:

    Lynx.dll!Lynx.MvcApplication.Application_Start.AnonymousMethod__2(string url = "/Scripts/modernizr-2.6.2.js", System.Uri currentRequestUrl = {System.Uri})  C#
>   i18n.dll!i18n.UrlLocalizer.FilterOutgoing(string url = "/Scripts/modernizr-2.6.2.js", System.Uri currentRequestUrl = {System.Uri})  C#
    i18n.dll!i18n.EarlyUrlLocalizer.LocalizeUrl(System.Web.HttpContextBase context = {System.Web.HttpContextWrapper}, string url = "/Scripts/modernizr-2.6.2.js", string langtag = "en-GB", System.Uri requestUrl = {System.Uri}, bool incomingUrl = false) C#
    i18n.dll!i18n.EarlyUrlLocalizer.ProcessOutgoing.AnonymousMethod__0(System.Text.RegularExpressions.Match match = {System.Text.RegularExpressions.Match}) C#
    System.dll!System.Text.RegularExpressions.RegexReplacement.Replace(System.Text.RegularExpressions.MatchEvaluator evaluator = {Method = {System.Reflection.RuntimeMethodInfo}}, System.Text.RegularExpressions.Regex regex, string input, int count = -1, int startat)   
    System.dll!System.Text.RegularExpressions.Regex.Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator, int count, int startat)  
    System.dll!System.Text.RegularExpressions.Regex.Replace(string input, System.Text.RegularExpressions.MatchEvaluator evaluator)  
    i18n.dll!i18n.EarlyUrlLocalizer.ProcessOutgoing(string entity, string langtag = "en-GB", System.Web.HttpContextBase context = {System.Web.HttpContextWrapper})  C#
    i18n.dll!i18n.ResponseFilter.Flush()    C#
    System.Web.dll!System.Web.HttpWriter.FilterIntegrated(bool finalFiltering = true, System.Web.Hosting.IIS7WorkerRequest wr)  
    System.Web.dll!System.Web.HttpResponse.FilterOutput()   
    System.Web.dll!System.Web.HttpApplication.CallFilterExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()   
    System.Web.dll!System.Web.HttpApplication.ExecuteStep(System.Web.HttpApplication.IExecutionStep step = {System.Web.HttpApplication.CallFilterExecutionStep}, ref bool completedSynchronously = false)   
    System.Web.dll!System.Web.HttpApplication.PipelineStepManager.ResumeSteps(System.Exception error)   
    System.Web.dll!System.Web.HttpApplication.BeginProcessRequestNotification(System.Web.HttpContext context, System.AsyncCallback cb)  
    System.Web.dll!System.Web.HttpRuntime.ProcessRequestNotificationPrivate(System.Web.Hosting.IIS7WorkerRequest wr = {System.Web.Hosting.IIS7WorkerRequest}, System.Web.HttpContext context = {System.Web.HttpContext})    
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext = 194144004, System.IntPtr moduleData, int flags) 
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags)   
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags) 
    System.Web.dll!System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(System.IntPtr rootedObjectsPointer, System.IntPtr nativeRequestContext, System.IntPtr moduleData, int flags)   
    [Appdomain Transition]  

If you can try setting breakpoints back along that chain you might be able to see where it goes wrong.

@turquoiseowl
Copy link
Owner

Ah yes, sorry, I also have a matching IncomingUrlFilters delegate:

            i18n.UrlLocalizer.IncomingUrlFilters += delegate(Uri url)
            {
                if (url.LocalPath.IndexOf("/Api", StringComparison.OrdinalIgnoreCase) != -1) {
                    return false; }
                if (url.LocalPath.IndexOf("xdomain", StringComparison.OrdinalIgnoreCase) != -1) {
                    return false; }
               //
                return true;
            };

@mmunchandersen
Copy link
Contributor Author

Thanks. As mentioned, when I use:

i18n.UrlLocalizer.IncomingUrlFilters += delegate(Uri url)
{
    if (url.LocalPath.Contains("/api"))
        return false;
    return true;
};

my Api GET calls (http://domain/api/xxx) works just fine.

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

2 participants