0

Need to manipulate the asp.net web-service web method inputs before it getting executed.

For example:

I have one web method called web1(string inp1). Now, I am calling this web method with the input inp1 value as "Jagan drop table", but I need to change the inp1 value as "Jagan" and then pass it to corresponding web method.

I don't want to replace this in each web method, but in common place (like common function or class).

Paul
  • 4,160
  • 3
  • 30
  • 56
Jagan T
  • 30
  • 1
  • 5
  • @SushantYelpale The OP has mentioned `asmx` in the question tag. – Rahul Sharma Jan 06 '20 at 06:24
  • I removed web api tag – Jagan T Jan 06 '20 at 06:45
  • I would recommend to use [SOAP extension](https://learn.microsoft.com/en-us/dotnet/api/system.web.services.protocols.soapextension?redirectedfrom=MSDN&view=netframework-4.8) for that case – Selim Yildiz Jan 06 '20 at 06:52
  • You should be using parameters and, to be frank, writing a common class for data handling is bread and butter stuff - you should know how to do this already. – Paul Jan 06 '20 at 09:28

2 Answers2

0

are you trying to deal with Sql injection? Just use sql parameters when you are building your queries to avoid it.

I do not think that this is good way to remove something from the incoming parameters without notice. It is better to check for the sql injection and raise an error if you have found.

You can use the ASP.NET middleware if you are looking for the way to inspect all incoming parameters. Like

public class SampleMiddleware
{
    private readonly RequestDelegate _next;

    public SampleMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        //you can have access for 
        httpContext.Request.Query
        httpContext.Request.Headers
        httpContext.Request.Body
    }
}

and you can make this SampleMiddleware.InvokeAsync to be executed for every method in the controller with the Microsoft.AspNetCore.Builder.UseMiddlewareExtensions

public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<SampleMiddleware>();
}
}
oleksa
  • 3,688
  • 1
  • 29
  • 54
  • Remember, `async` will depend on the version of .NET Framework and programming method (Classic ASP.NET, MVC, Razor Pages) being used. I wouldn't make anything too fancy, here, just stick to the basics. Also, usage across multiple functions does not depend on asynchronous execution; simply having an accessible class is enough. In some cases you can even get away with static class functions. Bang on with the SQL parameters, though. – Paul Jan 06 '20 at 09:40
0

One way to achieve the requirement is to use the Soap Extensions -

I am taking the code for the below site and trying to explain the same accordingly -

https://expertsys.hu/2017/10/11/renaming-asmx-webmethod-parameter-preserving-compatibility/

  1. Create the Soap Extension class.
  2. The whole processing happens in the processmessage call. If you see the "updateMessage" method which is called beforeSerialize ,this method parses and extracts the XML with input node "inp1" and replacing the value with the split operator which is according to your requirement. You could change further if need!
  3. The "ParameterValueChangedSoapExtensionAttribute" class which which will help specifying the Soap Extention class.
  4. All the other methods are helper classes to achieve the requirement.
public class ParameterValueChangedSoapExtension : SoapExtension
{
    private Stream streamChainedAfterUs = null;
    private Stream streamChainedBeforeUs = null;

    private const int STREAMBUFFERSIZE = 65535;

    private ParameterValueChangedSoapExtensionAttribute ParameterValueChangedSoapExtensionAttribute = null;

    public override Stream ChainStream(Stream stream)
    {
        if (stream == null)
        {
            throw new ArgumentNullException("stream");
        }
        Stream ret = null;
        this.streamChainedBeforeUs = stream;
        this.streamChainedAfterUs = new MemoryStream();
        ret = this.streamChainedAfterUs;
        return ret;
    }

    public override object GetInitializer(Type serviceType)
    {
        throw new NotSupportedException();
    }

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
    {
        if (attribute == null)
        {
            throw new ArgumentNullException("attribute");
        }
        object ret = attribute;
        return ret;
    }

    public override void Initialize(object initializer)
    {
        if (initializer == null)
        {
            throw new ArgumentNullException("initializer");
        }
        ParameterValueChangedSoapExtensionAttribute = initializer as ParameterValueChangedSoapExtensionAttribute;
        if (ParameterValueChangedSoapExtensionAttribute == null)
        {
            throw new InvalidOperationException(String.Format("initializer must be of type {0}, but its a {1}!", typeof(ParameterValueChangedSoapExtensionAttribute), initializer.GetType()));
        }
    }

    public override void ProcessMessage(SoapMessage message)
    {
        if (message == null)
        {
            throw new ArgumentNullException("message");
        }
        switch(message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                streamChainedAfterUs.Position = 0;
                Copy(streamChainedAfterUs, streamChainedBeforeUs);
                break;
            case SoapMessageStage.BeforeDeserialize:
                UpdateMessage(message);
                streamChainedAfterUs.Position = 0;
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
            default:
                throw new NotImplementedException(message.Stage.ToString());
        }
    }

    private void UpdateMessage(SoapMessage message)
    {
        var soapMsgAsString = ReadOriginalSoapMessage();
        var soapMsgRootNode = XElement.Parse(soapMsgAsString);
        var callDescriptorNode = FindCallDescriptorNode(soapMsgRootNode, message.MethodInfo.Name);
        var ns = callDescriptorNode.Name.Namespace;
        var originalNameWeLookFor = ns + ParameterValueChangedSoapExtensionAttribute.OriginalParameterName;
        var nodeWithOriginalName = callDescriptorNode.Elements().FirstOrDefault(i => i.Name == originalNameWeLookFor);
        if (nodeWithOriginalName != null)
        {
            //Here implement according to your need!
            nodeWithOriginalName.Value = nodeWithOriginalName.split(' ')[0];
            var nodeWithCurrentName = new XElement(ns + ParameterValueChangedSoapExtensionAttribute.CurrentParameterName, nodeWithOriginalName.Value);
            nodeWithOriginalName.AddAfterSelf(nodeWithCurrentName);
            nodeWithOriginalName.Remove();
        }
        WriteResultSoapMessage(soapMsgRootNode.ToString());
    }

    private XElement FindCallDescriptorNode(XElement soapMsgRootNode, string methodName)
    {
        XElement ret = null;
        var soapBodyName = soapMsgRootNode.Name.Namespace + "Body";
        var soapBodyNode = soapMsgRootNode.Elements().First(i => i.Name == soapBodyName);
        ret = soapBodyNode.Elements().First(i => i.Name.LocalName == methodName);
        return ret;
    }

    private void WriteResultSoapMessage(string msg)
    {
        streamChainedAfterUs.Position = 0;
        using (var sw = new StreamWriter(streamChainedAfterUs, Encoding.UTF8, STREAMBUFFERSIZE, true))
        {
            sw.Write(msg);
        }
    }

    private string ReadOriginalSoapMessage()
    {
        string ret = null;
        using (var sr = new StreamReader(streamChainedBeforeUs, Encoding.UTF8, false, STREAMBUFFERSIZE, true))
        {
            ret = sr.ReadToEnd();
        }
        return ret;
    }

    private void Copy(Stream from, Stream to)
    {
        using (var sr = new StreamReader(from, Encoding.UTF8, false, STREAMBUFFERSIZE, true))
        {
            using (var sw = new StreamWriter(to, Encoding.UTF8, STREAMBUFFERSIZE, true))
            {
                var content = sr.ReadToEnd();
                sw.Write(content);
            }
        }
    }
}


[AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
public class ParameterValueChangedSoapExtensionAttribute : SoapExtensionAttribute
{
    public override Type ExtensionType
    {
        get { return typeof(ParameterNameChangedSoapExtension); }
    }

    public override int Priority { get; set; }
    public string CurrentParameterName { get; private set; }
    public string OriginalParameterName { get; private set; }

    public ParameterValueChangedSoapExtensionAttribute()
    {
        this.CurrentParameterName = "inp1";
        this.OriginalParameterName = "inp1";
    }
}

Please go through the below link for more information on the SOAP Extensions -

Soap Extensions

SoapExtensionAttribute

Paul
  • 4,160
  • 3
  • 30
  • 56
MBB
  • 1,635
  • 3
  • 9
  • 19