public IActionResult Agent()
        {
            //mapagent only accepts GET or POST, so reject unsupported methods
            bool isGet = this.Request.Method == "GET";
            bool isPost = this.Request.Method == "POST";
            if (!isGet && !isPost)
            {
                return HttpBadRequest("Unsupported method: " + this.Request.Method);
            }

            //We need the current request url as the mapagent may need to reference this URL for certain operations
            //(for example: GetMapKml/GetLayerKml/GetFeaturesKml)
            String uri = string.Empty;
            try
            {
                //This is the workhorse behind the mapagent handler, the previously mysterious MgHttpRequest class
                MgHttpRequest request = new MgHttpRequest(uri);

                //MgHttpRequestParam is the set of key/value parameter pairs that you need to set up for the
                //MgHttpRequest instance. We extract the relevant parameters from the HttpContext and pass it
                //down
                MgHttpRequestParam param = request.GetRequestParam();

                //Extract any parameters from the http authentication header if there is one
                bool bGotAuth = ParseAuthenticationHeader(param, Request);

                if (isGet)
                {
                    PopulateGetRequest(param, Request);
                }
                else if (isPost)
                {
                    PopulatePostRequest(param, Request);
                }

                //A request is valid if it contains any of the following:
                //
                // 1. A SESSION parameter
                // 2. A USERNAME parameter (PASSWORD optional). If not specified the http authentication header is checked and extracted if found
                //
                //Whether these values are valid will be determined by MgSiteConnection in the MgHttpRequest handler when we come to execute it
                bool bValid = param.ContainsParameter("SESSION");
                if (!bValid)
                    bValid = param.ContainsParameter("USERNAME");

                if (!bValid)
                {
                    return MgUnauthorized();
                }

                return SendRequest(request);
            }
            catch (MgException ex)
            {
                return HandleMgException(ex);
            }
        }
        IActionResult SendRequest(MgHttpRequest request)
        {
            MgHttpRequestParam param = request.GetRequestParam();
            //This next line does all the grunt work. It's why you never have to actually set up a
            //MgSiteConnection/MgResourceService/MgFeatureService and do all this stuff yourself
            MgHttpResponse response = request.Execute();

            MgHttpResult result = response.GetResult();
            Response.StatusCode = result.GetStatusCode();
            if (Response.StatusCode == 200)
            {
                //MgDisposable is MapGuide's "object" class, so we need to do type
                //testing to find out the underlying derived type. The list of expected
                //types is small, so there isn't too much of this checking to do
                MgDisposable resultObj = result.GetResultObject();
                if (resultObj != null)
                {
                    Response.ContentType = result.GetResultContentType();

                    //Most of the applicable types have logic to return their content as XML in the form of a MgByteReader
                    MgByteReader outputReader = null;
                    if (resultObj is MgByteReader)
                    {
                        outputReader = (MgByteReader)resultObj;
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgFeatureReader)
                    {
                        //NOTE: This code path is not actually reached in MGOS 2.4 and if this code path ever
                        //does get reached, calling ToXml() on it is a potentially memory expensive operation.
                        //
                        //But we're doing this because this is how the official mapagent handler does it
                        //
                        //RFC 130 (http://trac.osgeo.org/mapguide/wiki/MapGuideRfc130) will hopefully address this problem
                        outputReader = ((MgFeatureReader)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgSqlDataReader)
                    {
                        //NOTE: This code path is not actually reached in MGOS 2.4 and if this code path ever
                        //does get reached, calling ToXml() on it is a potentially memory expensive operation.
                        //
                        //But we're doing this because this is how the official mapagent handler does it
                        //
                        //RFC 130 (http://trac.osgeo.org/mapguide/wiki/MapGuideRfc130) will hopefully address this problem
                        outputReader = ((MgSqlDataReader)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgDataReader)
                    {
                        //NOTE: This code path is not actually reached in MGOS 2.4 and if this code path ever
                        //does get reached, calling ToXml() on it is a potentially memory expensive operation.
                        //
                        //But we're doing this because this is how the official mapagent handler does it
                        //
                        //RFC 130 (http://trac.osgeo.org/mapguide/wiki/MapGuideRfc130) will hopefully address this problem
                        outputReader = ((MgDataReader)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgStringCollection)
                    {
                        outputReader = ((MgStringCollection)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgSpatialContextReader)
                    {
                        outputReader = ((MgSpatialContextReader)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgLongTransactionReader)
                    {
                        outputReader = ((MgSpatialContextReader)resultObj).ToXml();
                        return OutputReaderContent(outputReader);
                    }
                    else if (resultObj is MgHttpPrimitiveValue)
                    {
                        return Content(((MgHttpPrimitiveValue)resultObj).ToString());
                    }
                    else //Shouldn't get here
                    {
                        return HttpBadRequest("Not sure how to output: " + resultObj.ToString());
                    }
                }
                else
                {
                    //The operation may not return any content at all, so we do nothing
                    return Ok();
                }
            }
            else
            {
                return HandleMgHttpError(result);
            }
        }