FeatureLayer secured/proxy service request cancelled

4404
5
Jump to solution
01-22-2016 02:49 PM
ChrisSmith7
Frequent Contributor

I haven't quite tamped-down this issue, but I'm having trouble piping-in a SQL-sourced, secured layer into my map. Here's the code snippet:

featureLayer = FeatureLayer(this._objLayers.MyLayer.attColl.URL.val, {
  id: 'myLayer',
  mode: FeatureLayer.MODE_ONDEMAND,
  infoTemplate: popupTemplate,
  outFields: ["field1", "field2", "field3", "field4", "FOOBAR", "field6"]
});

I've found that if I remove the column [FOOBAR], it seems to be added to the map without issue. If I add [FOOBAR], the map doesn't load anything at the normal, starting extent. No errors are reported in console - fiddler just shows an open request (no response). If I zoom-in and reduce extent, some features begin to show, but console reports the message:

dojo.io.script error CancelError: Request canceled
   "dojo.io.script error"
   {
      [functions]: ,
      description: "Request canceled",
      dojoType: "cancel",
      log: undefined,
      message: "Request canceled",
      name: "CancelError",
      response: { },
      stack: undefined
   }

I tried debugging the proxy, but found nothing constructive - my assumption was that there were either unsafe chars, or maybe a length issue with the return. The latter didn't make sense, though, since the proxy should handle large requests.

As a test, I adjusted the data in the SQL back-end and hard-coded a text value maxing-out the column width. This was piped-in without issue, so I'm beginning to think the proxy is rejecting some unsafe chars.

Has anyone had a similar experience? I'm using the latest release version of the proxy from GitHub (1.1.0).

0 Kudos
1 Solution

Accepted Solutions
ChrisSmith7
Frequent Contributor

Ok, I think I've resolved it, for now at least. Probably not the best idea, but, if I hardcode encoding in fetchAndPassBackToClient(), everything works!

using (StreamReader sr = new StreamReader(byteStream))

becomes...

using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(28591)))

Here's the full method:

 private bool fetchAndPassBackToClient(System.Net.WebResponse serverResponse, HttpResponse clientResponse, bool ignoreAuthenticationErrors) {
        //System.Net.HttpWebResponse serverResponseAux = null;
        //var req = (HttpWebRequest)WebRequest.Create(serverResponse.ResponseUri);
        //serverResponseAux = (System.Net.HttpWebResponse)req.GetResponse();
        if (serverResponse != null) {
            using (Stream byteStream = serverResponse.GetResponseStream()) {
                // Text response
                if (serverResponse.ContentType.Contains("text") ||
                    serverResponse.ContentType.Contains("json") ||
                    serverResponse.ContentType.Contains("xml")) {
                    using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(28591)))
                    //using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(serverResponseAux.CharacterSet)))
                    //using (StreamReader sr = new StreamReader(byteStream)) 
                    {
                        string strResponse = sr.ReadToEnd();
                        if (
                            !ignoreAuthenticationErrors
                            && strResponse.Contains("error")
                            && (strResponse.Contains("\"code\": 498") || strResponse.Contains("\"code\": 499") || strResponse.Contains("\"code\":498") || strResponse.Contains("\"code\":499"))
                        )
                            return true;


                        //Copy the header info and the content to the reponse to client
                        copyHeaders(serverResponse, clientResponse);
                        clientResponse.Write(strResponse);
                    }
                } else {
                    // Binary response (image, lyr file, other binary file)


                    //Copy the header info to the reponse to client
                    copyHeaders(serverResponse, clientResponse);
                    // Tell client not to cache the image since it's dynamic
                    clientResponse.CacheControl = "no-cache";
                    byte[] buffer = new byte[32768];
                    int read;
                    while ((read = byteStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        clientResponse.OutputStream.Write(buffer, 0, read);
                    }
                    clientResponse.OutputStream.Close();
                }
                serverResponse.Close();
            }
        }
        return false;
    }

I suppose I'll mark this as the answer - if anyone has any better ideas, let me know!

View solution in original post

5 Replies
ChrisSmith7
Frequent Contributor

One thing to keep in mind if you're debugging proxy logs - unless it's an error, you will need to configure logLevel in the proxy.config - I don't think this is documented, at least I couldn't see it here: resource-proxy/README.md at master · Esri/resource-proxy · GitHub

This should be using .NET trace, so the enums will be honored:

Error - Output error-handling messages.

Info - Output informational messages, warnings, and error-handling messages.

Off - Output no tracing and debugging messages.

Verbose - Output all debugging and tracing messages.

Warning - Output warnings and error-handling messages.

https://msdn.microsoft.com/en-us/library/system.diagnostics.tracelevel(v=vs.110).aspx

E.g.:

<ProxyConfig allowedReferers="*"
            mustMatch="true"
            logFile="proxylog.txt"
            logLevel="Info">
</ProxyConfig>

If you are having trouble allowing ASP.NET to write the log files, try this following the guide here:

http://stackoverflow.com/questions/14653722/how-do-i-give-asp-net-permission-to-write-to-a-folder-in...

I was successful in giving full control of my local build's proxy folder to IIS_IUSRS on my local machine. I'm still having trouble figuring this out, but it seems almost certain that it's some encoding or unsafe chars issue...

0 Kudos
ChrisSmith7
Frequent Contributor

I had a chance to look more into this - it seems to be an issue with special chars... I'm not sure it's even a proxy issue, but, so far, I've found the request cancels as soon as the following chars are encountered:

*

#

¢

é

I have a PowerShell script I'm using to create a list of unique chars so I can debug easier:

$letters = @{} ; gc file.txt | select -Skip 2 | % { $_.ToCharArray() } | % { $letters[$_] = $true } ; $letters.Keys

I'm going through the list now and testing suspect chars - there's about 50 of them, unfortunately.

UPDATE:

Adding link to QueryTask.ExecuteAsync() /w Special Characters

0 Kudos
ChrisSmith7
Frequent Contributor

Just to isolate this a bit more, I tried loading a static (from a shapefile), secured map service requiring the proxy - the same encoding issue occurred, so it doesn't appear to be an SQL oddity. I then removed security on the SQL-based map service and removed the proxy rule in my mapping application - the layer loads without issue.

It appears there is some evidence that it is an encoding/decoding bug within the proxy - just need to isolate where.

0 Kudos
ChrisSmith7
Frequent Contributor

Ok, I think I've resolved it, for now at least. Probably not the best idea, but, if I hardcode encoding in fetchAndPassBackToClient(), everything works!

using (StreamReader sr = new StreamReader(byteStream))

becomes...

using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(28591)))

Here's the full method:

 private bool fetchAndPassBackToClient(System.Net.WebResponse serverResponse, HttpResponse clientResponse, bool ignoreAuthenticationErrors) {
        //System.Net.HttpWebResponse serverResponseAux = null;
        //var req = (HttpWebRequest)WebRequest.Create(serverResponse.ResponseUri);
        //serverResponseAux = (System.Net.HttpWebResponse)req.GetResponse();
        if (serverResponse != null) {
            using (Stream byteStream = serverResponse.GetResponseStream()) {
                // Text response
                if (serverResponse.ContentType.Contains("text") ||
                    serverResponse.ContentType.Contains("json") ||
                    serverResponse.ContentType.Contains("xml")) {
                    using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(28591)))
                    //using (StreamReader sr = new StreamReader(byteStream, Encoding.GetEncoding(serverResponseAux.CharacterSet)))
                    //using (StreamReader sr = new StreamReader(byteStream)) 
                    {
                        string strResponse = sr.ReadToEnd();
                        if (
                            !ignoreAuthenticationErrors
                            && strResponse.Contains("error")
                            && (strResponse.Contains("\"code\": 498") || strResponse.Contains("\"code\": 499") || strResponse.Contains("\"code\":498") || strResponse.Contains("\"code\":499"))
                        )
                            return true;


                        //Copy the header info and the content to the reponse to client
                        copyHeaders(serverResponse, clientResponse);
                        clientResponse.Write(strResponse);
                    }
                } else {
                    // Binary response (image, lyr file, other binary file)


                    //Copy the header info to the reponse to client
                    copyHeaders(serverResponse, clientResponse);
                    // Tell client not to cache the image since it's dynamic
                    clientResponse.CacheControl = "no-cache";
                    byte[] buffer = new byte[32768];
                    int read;
                    while ((read = byteStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        clientResponse.OutputStream.Write(buffer, 0, read);
                    }
                    clientResponse.OutputStream.Close();
                }
                serverResponse.Close();
            }
        }
        return false;
    }

I suppose I'll mark this as the answer - if anyone has any better ideas, let me know!

AndyMorgan1
New Contributor III

The encoding addition doesn't fix it for me.  I'm also using latest DotNet proxy (1.1.0), along with IE 11 + JS API 3.17 + ArcGIS 10.22.  The cancel error is caused by either of the following, specifically due to interrupting the map redrawing, as the response url points to the "export" task ( "/...proxy.ashx?http://myserver.domain/..../MapServer/export?")

1) Using LayerDrawingOptions on a dynamic map service to render a layer with a custom symbol

    drawingOptions.renderer = new SimpleRenderer(polygonSymbol);
    optionsArray[0] = drawingOptions;
    app.myMapServiceLayer.setLayerDrawingOptions(optionsArray);

2) Using LayerDrawingOptions with LabelClass on multiple layers within a dynamic map service

          var drawingOptionsLabelClass = new LayerDrawingOptions();
            var labelClass = new LabelClass({
                labelExpression: '[my_field_name]',
                labelPlacement: 'above-center',
                symbol: labelSymbol
            });
            drawingOptionsLabelClass.labelingInfo = [labelClass];
            drawingOptionsLabelClass.showLabels = true;
            optionsArray[1] = drawingOptionsLabelClass;
            optionsArray[2] = drawingOptionsLabelClass;
            app.SomeOtherMapServiceLayer.setLayerDrawingOptions(optionsArray);

No cancel errors are displayed when only applying LabelClass against one layer.

Not expecting help, just thought I'd point this out.  There may be no way to eliminate the console message because I suspect it's a case where the ESRI JS API's deferreds are being cancelled and "cancel error" is the generic catch all message.

From DoJo documentation:

dojo/errors/CancelError is the default error if a promise is canceled without a reason

0 Kudos