How to call the ProxyServcie?

I Copy the code from
http://docs.servicestack.net/http-utils#creating-a-proxy-using-http-utils

    [Route("/proxy")]
    public class Proxy : IRequiresRequestStream, IReturn<string>
    {
        public string Url { get; set; }
        public Stream RequestStream { get; set; }
    }
    //http://docs.servicestack.net/http-utils
    public class ProxyServcie : AppService
    {
        public object Any(Proxy request)
        {
            if (string.IsNullOrEmpty(request.Url))
                throw new ArgumentNullException("Url");

            var hasRequestBody = base.Request.Verb.HasRequestBody();
            try
            {
                var url = request.Url;
                var bytes = url.SendBytesToUrl(
                  method: base.Request.Verb,
                  requestBody: hasRequestBody ? request.RequestStream.ReadFully() : null,
                  contentType: hasRequestBody ? base.Request.ContentType : null,
                  accept: ((IHttpRequest)base.Request).Accept,
                  requestFilter: req => req.UserAgent = "Gistlyn",
                  responseFilter: res => base.Request.ResponseContentType = res.ContentType);

                return bytes;
            }
            catch (WebException webEx)
            {
                var errorResponse = (HttpWebResponse)webEx.Response;
                base.Response.StatusCode = (int)errorResponse.StatusCode;
                base.Response.StatusDescription = errorResponse.StatusDescription;
                var bytes = errorResponse.GetResponseStream().ReadFully();
                return bytes;
            }
        }
    }

then in winform project to call it ,

private void button1_Click(object sender, EventArgs e)
        {
            (var app = new AppService())
            {
                var Gateway = app.Gateway;
                var bytes = Gateway.Send(new Proxy { Url = "http://192.*.*.*/upfile/abc/1.xls", RequestStream = new MemoryStream() });
                logger.Info($"bytes:{bytes.SerializeToString()}");
                var savedFilePath = "C:\\ 1.xls";
                using (var ms = new MemoryStream(bytes.SerializeToBytes()))
                using (var fs = new FileStream(savedFilePath, FileMode.OpenOrCreate))
                {
                    ms.WriteTo(fs);
                    ms.Close();
                    fs.Close();
                }
            }
        }
public class AppService : Service
{
}

It will get error , I have set the value to Url , but the exceptin say the Url value is null.

有关调用实时(JIT)调试而不是此对话框的详细信息,
请参见此消息的结尾。

************** 异常文本 **************
400 ArgumentNullException
Code: ArgumentNullException, Message: 值不能为 null。
参数名: Url
Field Errors:
  [Url] ArgumentNullException:值不能为 null。
参数名: Url
Server StackTrace:
 [Proxy: 2017/4/8 9:23:19]:
[REQUEST: {}]
System.ArgumentNullException: 值不能为 null。
参数名: Url
   在 weixin.Services.ProxyServcie.Any(Proxy request) 位置 C:\...\ProxyService.cs:行号 22
   在 lambda_method(Closure , Object , Object )
   在 ServiceStack.Host.ServiceRunner`1.Execute(IRequest request, Object instance, TRequest requestDto)

How to call the ProxyService ?

A proxy is not a ServiceStack Service you call with a DTO, it’s acts like a proxy which forwards the HTTP request to the specified url.

You can call it with any HTTP Client, here’s an example using HTTP Utils:

using (var fs = new FileStream(savedFilePath, FileMode.OpenOrCreate))
{
    var bytes = fs.ReadFully();
    $$"{baseUrl}/proxy".AddQueryParam("url", "http://192.*.*.*/upfile/abc/1.xls")
       .PostBytesToUrl(bytes, contentType:"application/vnd.ms-excel");
}

Note I haven’t tested it, but you’d use it with something like the above.

For future reference the IRequiresRequestStream interface is an indicator that the Service is not meant to be called with a DTO + Service Client, it suggests that the Service intends to reads raw bytes directly from the HTTP Request Body.

I have accord to your advice to change the code, my purpose is want to get the Excel from url through proxy,
the excel address can’t visit directly, but can visit by proxy.

 private void button1_Click(object sender, EventArgs e)
        {
            using (new WaitDialogForm())
            using (var app = AppService)
            {
                var abc = "abc.test";
                var url = "http://192.*.*.*/upfile/abc/1.xls";
                
                var requestUrl = f.ApiUrl + "/proxy";
                var jwtToken = GetBearerToken();
                logger.Info($"jwtToken: {jwtToken}");
                logger.Info($"requestUrl: {requestUrl}");
                var respose = requestUrl.AddQueryParam("Url", url)
                        .PostBytesToUrl(requestBody: abc.ToUtf8Bytes()
                        , contentType: "application/vnd.ms-excel"
                        , requestFilter: req => req.AddBearerToken(jwtToken));

                logger.Info($"bytes:{respose.SerializeToString()}");
                var savedFilePath = "C:\\1.xls";
                using (var ms = new MemoryStream(respose))
                using (var fs = new FileStream(savedFilePath, FileMode.OpenOrCreate))
                {
                    ms.WriteTo(fs);
                    ms.Close();
                    fs.Close();
                }
            }
        }
        protected virtual IJsonServiceClient GetClient() => new JsonServiceClient(f.ApiUrl);
        private string GetBearerToken()
        {
            var authClient = GetClient();
            var bearerToken = authClient.Send(new Authenticate
            {
                provider = "credentials",
                UserName = userName,
                Password = passWord,
            }).BearerToken;
            return bearerToken;
        }

it run will get error, (405)method not allowed. , I didn’t restrict the methods .

有关调用实时(JIT)调试而不是此对话框的详细信息,
请参见此消息的结尾。

************** 异常文本 **************
System.Net.WebException: 远程服务器返回错误: (405) 不允许的方法。
   在 System.Net.HttpWebRequest.GetResponse()
   在 ServiceStack.Net40PclExport.GetResponse(WebRequest webRequest)
   在 ServiceStack.HttpUtils.SendBytesToUrl(String url, String method, Byte[] requestBody, String contentType, String accept, Action`1 requestFilter, Action`1 responseFilter)
   在 ServiceStack.HttpUtils.PostBytesToUrl(String url, Byte[] requestBody, String contentType, String accept, Action`1 requestFilter, Action`1 responseFilter)
   在 weixin.dw.FmTest.button1_Click(Object sender, EventArgs e) 位置 C:\...\FmTest.cs:行号 41
   在 System.Windows.Forms.Control.OnClick(EventArgs e)
   在 System.Windows.Forms.Button.OnClick(EventArgs e)
   在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   在 System.Windows.Forms.Control.WndProc(Message& m)
   在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
   在 System.Windows.Forms.Button.WndProc(Message& m)
   在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I’m assuming that’s an error with the downstream server. You need to look at the raw HTTP Headers to see what’s really being returned by which server.

My code is run in test enviroment , It is the website and the winform project in one machine.

I have used the swagger UI to test the proxy 's get method, It works , you can see the response header , How I can see the raw HTTP Headers ?

Using a tool like Fiddler or WireShark.

You should get familiar with these HTTP tools in order to diagnose application issues like this, you’re in the best position to diagnose your local issues, we can’t tell what it is from here.

thanks, Now I Have used the Fiddler to caputre the raw HTTP Header and response .
Request Headers

POST http://127.0.0.1:5001/ssapi//proxy?Url=https%3a%2f%2f...930094122516.xls HTTP/1.1
Content-Type: application/vnd.ms-excel
Accept: */*
Accept-Encoding: gzip,deflate
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IkxnYSJ9.eyJzdWIiOjE0NDU4OSwiaWF0IjoxNDkxNjQ5NjEyLCJleHAiOjE1MjMxODU2MTIsIm5hbWUiO...HlhZrliqEiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ3ZWl4aW5kdyJ9.yuBBCAHJOPTahZ2LB16tQo9D-RnDEepFmcjtGoyKdPE
Host: 127.0.0.1:5001
Content-Length: 8
Expect: 100-continue

abc.test

Reponse Headers

HTTP/1.1 405 Method Not Allowed
Cache-Control: private
Content-Length: 1202
Content-Type: application/octet-stream
Vary: Accept
Server: Microsoft-IIS/7.5
X-Powered-By: ServiceStack/4.58 Win32NT/.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=zEdncEs7rUrR3SGrx1he; path=/; HttpOnly
Set-Cookie: ss-pid=CQLjH8gH4RasFiMiy0Ay; expires=Wed, 08-Apr-2037 11:06:52 GMT; path=/; HttpOnly
X-Powered-By: ASP.NET
Date: Sat, 08 Apr 2017 11:06:52 GMT

That only shows the proxy, you can’t tell if the response originated from the downstream server by looking at the proxy http traffic. Have you tried debugging the Proxy Service? i.e. putting a breakpoint on the Exception?

Sorry, It’s my problem , in the code ProxyServcie is url.SendBytesToUrl, but I set the url is a excel link, so it will get Method Not Allowed.
In Fact, I only want to get the excel content through proxy, the below code is enough. thanks.

 var bytes = url.GetBytesFromUrl();