隐藏

ASP.NET通过HttpModule实现过滤WebService的请求调用修改返回结果

发布:2021/7/13 16:43:58作者:管理员 来源:本站 浏览次数:948

背景

之前一个WebService服务用java写的,想改为.net重新开发一下,客户端的代码不变,却遇到了一个比较棘手的问题(当时客户端代码写的不够灵活),就是SOAP协议的响应格式中关于命名空间和命名空间前缀的问题。
举个最简单的例子:
java的WebService相关代码(基于Spring boot)如下:
WebService接口-IWebServiceTest.java

package com.example.soapdemo;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public interface IWebServiceTest {
    @WebMethod
    String sayHello();
}

 

WebService实现类-WebServiceTestImpl.java

package com.example.soapdemo;
import javax.jws.WebService;
@WebService
public class WebServiceTestImpl implements IWebServiceTest {
    @Override
    public String sayHello() {
        return "Hello World";
    }
}


服务启动类-SoapdemoApplication

package com.example.soapdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.xml.ws.Endpoint;
@SpringBootApplication
public class SoapdemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SoapdemoApplication.class, args);
        String url = "http://localhost:8081/ws";
        Endpoint.publish(url, new WebServiceTestImpl());
        System.out.println("发布webservice成功!");
    }
}

   

SoapUI调用示例:
在这里插入图片描述
请求结果中会自动增加一个命名空间和命名空间前缀。
改为C#实现后代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml.Serialization;
using System.Text;

/// <summary>
/// WebService 的摘要说明
/// </summary>
[WebService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {

    private System.Xml.Serialization.XmlSerializer serializer = null;
    public WebService () {

        //如果使用设计的组件,请取消注释以下行
        //InitializeComponent();
    }

    [WebMethod]
    public string SayHello()
    {
        return "Hello World";
    }
}


SoapUI调用示例如下:
在这里插入图片描述
方法调用结果对比
java

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:sayHelloResponse xmlns:ns2="http://soapdemo.example.com/">
         <return>Hello World</return>
      </ns2:sayHelloResponse>
   </S:Body>
</S:Envelope>


.net

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <SayHelloResponse xmlns="http://tempuri.org/">
         <SayHelloResult>Hello World</SayHelloResult>
      </SayHelloResponse>
   </soap:Body>
</soap:Envelope>

 

解决办法

使用了一个笨方法实现把c#的WebMethod的返回结果改为象java的结果一样。
增加一个HttpMoudle,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// AllHttpModule 的摘要说明
/// </summary>
public class AllHttpModule : IHttpModule
{
    public AllHttpModule()
    {
        //
        // TODO: 在此处添加构造函数逻辑
        //
    }

    public void Dispose()
    {
        //throw new NotImplementedException();
    }

    public void Init(HttpApplication context)
    {
        context.PreSendRequestContent += context_PreSendRequestContent;
    }

    private void context_PreSendRequestContent(object sender, EventArgs e)
    {
        HttpApplication ctx = sender as HttpApplication;
        if (ctx.Request.Url.ToString().Contains("WebService.asmx"))
        {
            if (ctx.Request.HttpMethod == "POST")
            {                
                string result = ctx.Context.Request.RequestContext.HttpContext.Items["cust-result"] as string;      //从RequestContext中获取过滤处理后的返回结果
                if (!String.IsNullOrEmpty(result))
                {
                    ctx.Response.Clear();               //清除原返回结果
                    ctx.Response.Write(result);         //返回新结果
                }
            }
        }
    }
}


web.config中增加配置如下

<?xml version="1.0" encoding="utf-8"?>

<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->

<configuration>

    <system.web>
      <compilation debug="true" targetFramework="4.0" />
        <!--<httpModules>
            <add name="AllHttpModule" type="AllHttpModule"/>
        </httpModules>-->
    </system.web>
    <system.webServer>
        <modules>
            <add name="AllHttpModule" type="AllHttpModule"/>
        </modules>
    </system.webServer>
</configuration>

  

修改webservice代码,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml.Serialization;
using System.Text;

/// <summary>
/// WebService 的摘要说明
/// </summary>
[WebService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {

    private System.Xml.Serialization.XmlSerializer serializer = null;
    public WebService () {

        //如果使用设计的组件,请取消注释以下行
        //InitializeComponent();
    }

    [WebMethod]
    public string SayHello()
    {
        #region 可以根据需要对返回结果的数据做处理

        StringBuilder sb = new StringBuilder();
        sb.AppendLine("<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">");
        sb.AppendLine("  <S:Body>");
        sb.AppendLine("    <ns2:sayHelloResponse xmlns:ns2=\"http://soapdemo.example.com/\">");
        sb.AppendLine("      <return>Hello World</return>");
        sb.AppendLine("    </ns2:sayHelloResponse>");
        sb.AppendLine("  </S:Body>");
        sb.AppendLine("</S:Envelope>");
        //把要返回的内容放入RequestContext
        HttpContext.Current.Request.RequestContext.HttpContext.Items["cust-result"] = sb.ToString();

        #endregion

        return "Hello World";
    }
}


重新使用SoapUI调用如下:
在这里插入图片描述