{"id":13734923,"url":"https://github.com/DigDes/SoapCore","last_synced_at":"2025-05-08T11:31:30.223Z","repository":{"id":15051343,"uuid":"77414336","full_name":"DigDes/SoapCore","owner":"DigDes","description":"SOAP extension for ASP.NET Core","archived":false,"fork":false,"pushed_at":"2024-11-05T17:56:26.000Z","size":1832,"stargazers_count":1006,"open_issues_count":4,"forks_count":378,"subscribers_count":35,"default_branch":"develop","last_synced_at":"2024-11-13T10:29:19.825Z","etag":null,"topics":["middleware","soap"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DigDes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-27T00:39:44.000Z","updated_at":"2024-11-12T22:13:36.000Z","dependencies_parsed_at":"2023-01-13T18:14:09.664Z","dependency_job_id":"e0f9871e-7bd1-401c-bb8b-f75293822c6e","html_url":"https://github.com/DigDes/SoapCore","commit_stats":{"total_commits":813,"total_committers":144,"mean_commits":5.645833333333333,"dds":0.8585485854858549,"last_synced_commit":"dfa51c3f3687f1cc86c6106465aad6713ab97b8f"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DigDes%2FSoapCore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DigDes%2FSoapCore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DigDes%2FSoapCore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DigDes%2FSoapCore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DigDes","download_url":"https://codeload.github.com/DigDes/SoapCore/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224727169,"owners_count":17359531,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["middleware","soap"],"created_at":"2024-08-03T03:01:01.225Z","updated_at":"2025-05-08T11:31:30.165Z","avatar_url":"https://github.com/DigDes.png","language":"C#","funding_links":[],"categories":["others","Libraries","C\\#"],"sub_categories":["API and RPC"],"readme":"# SoapCore\n\n[![NuGet Version](https://img.shields.io/nuget/v/SoapCore.svg)](https://www.nuget.org/packages/SoapCore/) ![](https://github.com/DigDes/SoapCore/workflows/CI/badge.svg) [![Stack Overflow](https://img.shields.io/badge/stackoverflow-questions-blue?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/soapcore)\n\nSOAP protocol middleware for ASP.NET Core\n\nBased on Microsoft article: [Custom ASP.NET Core Middleware Example](https://blogs.msdn.microsoft.com/dotnet/2016/09/19/custom-asp-net-core-middleware-example/).\n\nSupport ref\\out params, exceptions. Works with legacy SOAP\\WCF-clients.\n\n## Getting Started\n\n### Requirements\n\nThe following frameworks are supported:\n\n- .NET 8.0 (using ASP.NET Core 8.0)\n- .NET Core 3.1 (using ASP.NET Core 3.1)\n- .NET Standard 2.0-2.1 (using ASP.NET Core 2.1)\n\n### Installing\n\n`PM\u003e Install-Package SoapCore`\n\nThere are 2 different ways of adding SoapCore to your ASP.NET Core website. If you are using ASP.NET Core 3.1 or higher with endpoint routing enabled (the default):\n\nIn Startup.cs:\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddSoapCore();\n    services.TryAddSingleton\u003cServiceContractImpl\u003e();\n    services.AddMvc();\n}\n\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\n{\n    app.UseRouting();\n\n    app.UseEndpoints(endpoints =\u003e {\n        endpoints.UseSoapEndpoint\u003cServiceContractImpl\u003e(opt =\u003e\n\t{\n\t\topt.Path = \"/ServicePath.asmx\",\n\t\topt.SoapSerializer = SoapSerializer.DataContractSerializer\n\t});\n    });\n    \n}\n```\n\nIf you are using ASP.NET Core 2.1 (i.e., on .NET Framework, .NET Core 2.1, or another .NET Standard 2.0 compliant platform):\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    services.AddSoapCore();\n    services.TryAddSingleton\u003cServiceContractImpl\u003e();\n    services.AddMvc();\n}\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\n{\n    app.UseSoapEndpoint\u003cServiceContractImpl\u003e(\"/ServicePath.asmx\", new SoapEncoderOptions());\n}\n```\n\n### Using with custom implementation of Serialization\n\nThere is an optional feature included where you can implment the ISoapCoreSerializer to built your own custom serializar for body.\n\nIn Startup.cs:\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    ...\n    services.AddSoapCore();\n    services.TryAddSingleton\u003cServiceContractImpl\u003e();\n    services.AddCustomSoapMessageSerializer\u003cCustomeBodyMessageSerializerImpl\u003e();  //Add Your Custom Implementation or Extend Default Serializer\n\n    services.AddMvc();\n    ...\n}\n\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\n{\n    app.UseSoapEndpoint\u003cServiceContractImpl\u003e(soapCoreOptions =\u003e\n    {\n        soapCoreOptions.Path = \"/ServicePath.asmx\";\n        soapCoreOptions.UseCustomSerializer\u003cCustomeBodyMessageSerializerImpl\u003e();  //Specify the Service to Use Service Soap Message Serializer\n        soapCoreOptions.SoapSerializer = SoapSerializer.DataContractSerializer;\n        ...\n    });\n}\n\n```\n\n### Using with legacy WCF/WS\n\nIt is possible to use SoapCore with .NET legacy WCF and Web Services, both as client and service.\n\nPrimary point here is to use XmlSerializer and properly markup messages and operations with xml serialization attributes. You may use legacy pre-generated wrappers to obtain these contracts or implement them manually. Extended example is available under serialization tests project.\n\n### Using with external WSDL / XSD schemas\n\nThere is an optional feature included where you can instead of generating service description from code get the service description from files stored on the server.\n\nTo use it, add a setting like this to appsettings\n\n```json\n\"FileWSDL\": {\n  \"UrlOverride\": \"\",\n  \"SchemeOverride\": \"\",\n  \"VirtualPath\": \"\",\n  \"WebServiceWSDLMapping\": {\n    \"Service.asmx\": {\n      \"UrlOverride\": \"Management/Service.asmx\",\n      \"WsdlFile\": \"snapshotpull.wsdl\",\n      \"SchemaFolder\": \"Schemas\",\n      \"WsdlFolder\": \"Schemas\"\n    }\n  }\n}\n```\n\n* UrlOverride - can be used to override the URL in the service description. This can be useful if you are behind a firewall.\n* SchemeOverride - can be used to override the HTTP Scheme in the service description. This can be useful if you are behind a firewall and the firewall sets the X-Forwarded-Host header, but the internal HTTP scheme is not the same as the external.\n* VirtualPath - can be used if you like to add a path between the base URL and service. \n* WebServiceWSDLMapping\n  * UrlOverride - can be used to override the URL for a specific WSDL mapping. This can be useful if you want to host different services under different folder.\n  * Service.asmx - is the endpoint of the service you expose. You can have more than one.\n  * WsdlFile - is the name of the WSDL on disc.\n  * SchemaFolder - if you import XSD from WSDL, this is the folder where the Schemas are stored on disc.\n  * WsdlFolder - is the folder that the WSDL file is stored on disc.\n\n\nTo read the setting you can do the following\n\nIn Startup.cs:\n\n```csharp\nvar settings = Configuration.GetSection(\"FileWSDL\").Get\u003cWsdlFileOptions\u003e();\n\n// For case-insensitive mapping, if you are using \"SoapCoreOptions.CaseInsensitivePath = true\" - otherwise URLs with different casing won't be mapped correctly\n//var settings = Configuration.GetSection(\"FileWSDL\").Get\u003cWsdlFileOptionsCaseInsensitive\u003e();\n\nsettings.AppPath = env.ContentRootPath; // The hosting environment root path\n...\n\napp.UseSoapEndpoint\u003cServiceContractImpl\u003e(\"/Service.asmx\", new SoapEncoderOptions(), SoapSerializer.XmlSerializer, false, null, settings);\n```\n\nIf the WsdFileOptions parameter is supplied then this feature is enabled / used.\n\n### References\n\n- [stackify.com/soap-net-core](https://stackify.com/soap-net-core/)\n\n### Tips and Tricks\n\n#### Extending the pipeline\n\nIn your ConfigureServices method, you can register some additional items to extend the pipeline:\n\n- services.AddSoapMessageInspector() - add a custom MessageInspector. This function is similar to the `IDispatchMessageInspector` in WCF. The newer `IMessageInspector2` interface allows you to register multiple inspectors, and to know which service was being called.\n- services.AddSingleton\u003cMyOperatorInvoker\u003e() - add a custom OperationInvoker. Similar to WCF's `IOperationInvoker` this allows you to override the invoking of a service operation, commonly to add custom logging or exception handling logic around it.\n- services.AddSoapMessageProcessor() - add a custom SoapMessageProcessor. Similar to ASP.NET Cores middlewares, this allows you to inspect the message on the way in and out. You can also short-circuit the message processing and return your own custom message instead. Inspecting and modifying HttpContext is also possible\n\n#### Using ISoapMessageProcessor()\n\n```csharp\n//Add this to ConfigureServices in Startup.cs\n\nservices.AddSoapMessageProcessor(async (message, httpcontext, next) =\u003e\n{\n\tvar bufferedMessage = message.CreateBufferedCopy(int.MaxValue);\n\tvar msg = bufferedMessage.CreateMessage();\n\tvar reader = msg.GetReaderAtBodyContents();\n\tvar content = reader.ReadInnerXml();\n\n\t//now you can inspect and modify the content at will.\n\t//if you want to pass on the original message, use bufferedMessage.CreateMessage(); otherwise use one of the overloads of Message.CreateMessage() to create a new message\n\tvar originalMessage = bufferedMessage.CreateMessage();\n\n\t//pass the modified message on to the rest of the pipe.\n\tvar responseMessage = await next(message);\n\n\t//Inspect and modify the contents of returnMessage in the same way as the incoming message.\n\t//finish by returning the modified message.\n\n\treturn responseMessage;\n});\n```\n\n#### How to get custom HTTP header in SoapCore service\n\nUse interface IServiceOperationTuner to tune each operation call.\n\nCreate class that implements IServiceOperationTuner.\nParameters in Tune method:\n\n- httpContext - current HttpContext. Can be used to get http headers or body.\n- serviceInstance - instance of your service.\n- operation - information about called operation.\n\n```csharp\npublic class MyServiceOperationTuner : IServiceOperationTuner\n{\n    public void Tune(HttpContext httpContext, object serviceInstance, SoapCore.ServiceModel.OperationDescription operation)\n    {\n        if (operation.Name.Equals(\"SomeOperationName\"))\n        {\n            MyService service = serviceInstance as MyService;\n            string result = string.Empty;\n\n            StringValues paramValue;\n            if (httpContext.Request.Headers.TryGetValue(\"some_parameter\", out paramValue))\n            {\n                result = paramValue[0];\n            }\n\n            service.SetParameterForSomeOperation(result);\n        }\n    }\n}\n```\n\nRegister MyServiceOperationTuner in Startup class:\n\n```csharp\npublic class Startup\n{\n    public void ConfigureServices(IServiceCollection services)\n    {\n        // ...\n        services.AddSoapServiceOperationTuner(new MyServiceOperationTuner());\n        //...\n    }\n    // ...\n}\n```\n\nChange your service to get the possibility to store information from http headers:\n\n```csharp\npublic class MyService : IMyServiceService\n{\n    // Use ThreadLocal or some of thread synchronization stuff if service registered as singleton.\n    private ThreadLocal\u003cstring\u003e _paramValue = new ThreadLocal\u003cstring\u003e() { Value = string.Empty };\n\n    // ...\n\n    public void SetParameterForSomeOperation(string paramValue)\n    {\n        _paramValue.Value = paramValue;\n    }\n\n    public string SomeOperationName()\n    {\n        return \"Param value from http header: \" + _paramValue.Value;\n    }\n}\n```\n\n#### Additional namespace declaration attributes in envelope\n\nAdding additional namespaces to the **SOAP Envelope** can be done by populating `SoapEncoderOptions.AdditionalEnvelopeXmlnsAttributes` parameter.\n\n```csharp\n....\nendpoints.UseSoapEndpoint\u003cIService\u003e(opt =\u003e\n{\n\topt.Path = \"/ServiceWithAdditionalEnvelopeXmlnsAttributes.asmx\";\n\topt.AdditionalEnvelopeXmlnsAttributes = new Dictionary\u003cstring, string\u003e()\n\t{\n\t\t{ \"myNS\", \"http://schemas.someting.org\" },\n\t\t{ \"arr\", \"http://schemas.microsoft.com/2003/10/Serialization/Arrays\" }\n\t};\n});\n...\n```\n\nThis code will put `xmlns:myNS=\"...` and `xmlns:arr=\"...` attributes in `Envelope` and message will look like:\n\n```xml\n\u003cs:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" ... xmlns:myNS=\"http://schemas.someting.org\" xmlns:arr=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"\u003e\n...\n    \u003cmyNS:StringList\u003e\n        \u003carr:string\u003eError: one\u003c/arr:string\u003e\n        \u003carr:string\u003eError: two\u003c/arr:string\u003e\n    \u003c/fin:StringList\u003e\n...\n```\n\ninstead of:\n\n```xml\n\u003cs:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" ... \u003e\n...\n    \u003cd3p1:StringList xmlns:d4p1=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\"\u003e\n        \u003cd4p1:string\u003eError: one\u003c/arr:string\u003e\n        \u003cd4p1:string\u003eError: two\u003c/arr:string\u003e\n    \u003c/d3p1:StringList\u003e\n...\n```\n### Not implemented\nWCF and legacy WebService supports many scenarios and lots of attributes. SoapCore only supports the most common patterns.\nStuff that are not supported includes:\n* XmlIncludeAttribute/SoapIncludeAttribute\n* SoapDocumentMethodAttribute\n* \n\n### Contributing\n\nSee [Contributing guide](CONTRIBUTING.md)\n\n### Contributors\n\n\u003ca href=\"https://github.com/digdes/soapcore/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contributors-img.web.app/image?repo=digdes/soapcore\" /\u003e\n\u003c/a\u003e\n\nMade with [contributors-img](https://contributors-img.web.app).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDigDes%2FSoapCore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDigDes%2FSoapCore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDigDes%2FSoapCore/lists"}