Need Raw XML For Request & Response In UPS API (.N

2019-09-06 17:30发布

问题:

The answer to this may be painfully obvious. But need some help...

I'm currently using the UPS API/Service to generate test labels. Everything is working great. But to get it certified, I have to send UPS the raw XML from the requests & responses.

I'm not sending raw xml, but rather using the service and its various properties. Is there a raw XML returned somewhere within the shipment result? Or do have to manually serialize the request & responses just to satisfy what UPS wants in their review?

Here's my code (everything works, I'm able to generate a label. But how do I get request & response xml?)

try
        {
            ShipService shpSvc = new ShipService();
            ShipmentRequest shipmentRequest = new ShipmentRequest();
            UPSSecurity upss = new UPSSecurity();
            UPSSecurityServiceAccessToken upssSvcAccessToken = new UPSSecurityServiceAccessToken();
            upssSvcAccessToken.AccessLicenseNumber = s.APIKey;
            upss.ServiceAccessToken = upssSvcAccessToken;
            UPSSecurityUsernameToken upssUsrNameToken = new UPSSecurityUsernameToken();
            upssUsrNameToken.Username = s.Username;
            upssUsrNameToken.Password = s.Password;
            upss.UsernameToken = upssUsrNameToken;
            shpSvc.UPSSecurityValue = upss;
            RequestType request = new RequestType();

            String[] requestOption = { "nonvalidate" };
            request.RequestOption = requestOption;
            shipmentRequest.Request = request;                

    ShipmentType shipment = new ShipmentType();                
            ShipperType shipper = new ShipperType();
            shipper.ShipperNumber = s.ShipperAccountNumber;
            PaymentInfoType paymentInfo = new PaymentInfoType();

    ShipmentChargeType shpmentCharge = new ShipmentChargeType();
            BillShipperType billShipper = new BillShipperType();
            billShipper.AccountNumber = s.ShipperAccountNumber;
            shpmentCharge.BillShipper = billShipper;
            shpmentCharge.Type = "01";

    ShipmentChargeType[] shpmentChargeArray = { shpmentCharge };
            paymentInfo.ShipmentCharge = shpmentChargeArray;
            shipment.PaymentInformation = paymentInfo;
            ShipWebReference.ShipAddressType shipperAddress = new ShipWebReference.ShipAddressType();
            String[] addressLine = { s.ShipperAddressLine };

    shipperAddress.AddressLine = addressLine;
            shipperAddress.City = s.ShipperCity;
            shipperAddress.PostalCode = s.ShipperZip;
            shipperAddress.StateProvinceCode = s.ShipperState;
            shipperAddress.CountryCode = "US";
            shipperAddress.AddressLine = addressLine;
            shipper.Address = shipperAddress;
            shipper.Name = s.ShipperName;
            shipper.AttentionName = s.ShipperName;
            ShipPhoneType shipperPhone = new ShipPhoneType();
            shipperPhone.Number = s.ShipperPhone;
            shipper.Phone = shipperPhone;
            shipment.Shipper = shipper;
            ShipFromType shipFrom = new ShipFromType();

    ShipWebReference.ShipAddressType shipFromAddress = new ShipWebReference.ShipAddressType();
            String[] shipFromAddressLine = { s.ShipperAddressLine };
            shipFromAddress.AddressLine = addressLine;
            shipFromAddress.City = s.ShipperCity;
            shipFromAddress.PostalCode = s.ShipperZip;
            shipFromAddress.StateProvinceCode = s.ShipperState;
            shipFromAddress.CountryCode = "US";
            shipFrom.Address = shipFromAddress;
            shipFrom.AttentionName = s.ShipperName;
            shipFrom.Name = s.ShipperName;
            shipment.ShipFrom = shipFrom;

    ShipToType shipTo = new ShipToType();
            ShipToAddressType shipToAddress = new ShipToAddressType();
            String[] addressLine1 = { s.ShipToAddressLine };
            shipToAddress.AddressLine = addressLine1;
            shipToAddress.City = s.ShipToCity;
            shipToAddress.PostalCode = s.ShipToZip;
            shipToAddress.StateProvinceCode = s.ShipToState;
            shipToAddress.CountryCode = "US";
            shipTo.Address = shipToAddress;
            shipTo.AttentionName = s.ShipToName;
            shipTo.Name = s.ShipToName;

            ShipPhoneType shipToPhone = new ShipPhoneType();
            shipToPhone.Number = s.ShipToPhone;
            shipTo.Phone = shipToPhone;
            shipment.ShipTo = shipTo;
            ServiceType service = new ServiceType();

            service.Code = "03";
            shipment.Service = service;
            PackageType package = new PackageType();
            PackageWeightType packageWeight = new PackageWeightType();
            packageWeight.Weight = s.PackageWeight;
            ShipUnitOfMeasurementType uom = new ShipUnitOfMeasurementType();
            uom.Code = "LBS";
            packageWeight.UnitOfMeasurement = uom;
            package.PackageWeight = packageWeight;
            PackagingType packType = new PackagingType();
            packType.Code = "02";
            package.Packaging = packType;
            PackageType[] pkgArray = { package };
            shipment.Package = pkgArray;
            LabelSpecificationType labelSpec = new LabelSpecificationType();
            LabelStockSizeType labelStockSize = new LabelStockSizeType();
            labelStockSize.Height = "6";
            labelStockSize.Width = "4";
            labelSpec.LabelStockSize = labelStockSize;
            LabelImageFormatType labelImageFormat = new LabelImageFormatType();
            LabelDeliveryType labelDel = new LabelDeliveryType();
            labelDel.LabelLinksIndicator = "";
            labelImageFormat.Code = "GIF";

            PackageServiceOptionsType packServiceOptions = new PackageServiceOptionsType();
            PackageDeclaredValueType decType = new PackageDeclaredValueType();
            decType.CurrencyCode = "USD";
            decType.MonetaryValue = s.PackageValue;
            packServiceOptions.DeclaredValue = decType;
            package.PackageServiceOptions = packServiceOptions;


            labelSpec.LabelImageFormat = labelImageFormat;
            ShipmentTypeShipmentServiceOptions shipServOpt = new ShipmentTypeShipmentServiceOptions();

            shipment.ShipmentServiceOptions = shipServOpt;


            shipmentRequest.LabelSpecification = labelSpec;
            shipmentRequest.Shipment = shipment;

            System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
            Console.WriteLine(shipmentRequest);

            shipmentResponse = shpSvc.ProcessShipment(shipmentRequest);               

        }

回答1:

I faced pretty the same problem, and luckily for you I resolved the problem ;)

You need something to register a SOAP Extension:

 [ReflectionPermission(SecurityAction.Demand, Unrestricted = true)]
    public static void RegisterSoapExtension(Type type, int priority, PriorityGroup group)
    {
        if (!type.IsSubclassOf(typeof(SoapExtension)))
        {
            throw new ArgumentException("Type must be derived from SoapException.", "type");
        }

        if (priority < 1)
        {
            throw new ArgumentOutOfRangeException("priority", priority, "Priority must be greater or equal to 1.");
        }

        // get the current web services settings...  
        WebServicesSection wss = WebServicesSection.Current;

        // set SoapExtensionTypes collection to read/write...  
        FieldInfo readOnlyField = typeof(System.Configuration.ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
        readOnlyField.SetValue(wss.SoapExtensionTypes, false);

        // inject SoapExtension...  
        //wss.SoapExtensionTypes.Add(new SoapExtensionTypeElement(type, priority, group));

        System.Web.Services.Configuration.SoapExtensionTypeElement soapInterceptor = new SoapExtensionTypeElement();
        soapInterceptor.Type = type;
        soapInterceptor.Priority = priority;
        soapInterceptor.Group = group;
        wss.SoapExtensionTypes.Add(soapInterceptor);

        // set SoapExtensionTypes collection back to readonly and clear modified flags...  
        MethodInfo resetModifiedMethod = typeof(System.Configuration.ConfigurationElement).GetMethod("ResetModified", BindingFlags.NonPublic | BindingFlags.Instance);
        resetModifiedMethod.Invoke(wss.SoapExtensionTypes, null);
        MethodInfo setReadOnlyMethod = typeof(System.Configuration.ConfigurationElement).GetMethod("SetReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
        setReadOnlyMethod.Invoke(wss.SoapExtensionTypes, null);
    }

You need to define the actual extension:

/// <summary>
/// SOAP Extension that traces the SOAP request and
/// SOAP response to a SOAP API Web service. 
/// </summary>
public class TraceExtension : SoapExtension
{
    private Stream oldStream;
    private Stream newStream;

    private static XmlDocument xmlRequest;

    /// <summary>
    /// Gets the outgoing XML request
    /// </summary>
    public static XmlDocument XmlRequest
    {
        get { return xmlRequest; }
    }

    private static XmlDocument xmlResponse;

    /// <summary>
    /// Gets the incoming XML response
    /// </summary>
    public static XmlDocument XmlResponse
    {
        get { return xmlResponse; }
    }

    /// <summary>
    /// Save the Stream representing the SOAP request
    /// or SOAP response into a local memory buffer. 
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    public override Stream ChainStream(Stream stream)
    {
        oldStream = stream;
        newStream = new MemoryStream();
        return newStream;
    }

    /// <summary>
    /// If the SoapMessageStage is such that the SoapRequest or
    /// SoapResponse is still in the SOAP format to be sent or received,
    /// save it to the xmlRequest or xmlResponse property.
    /// </summary>
    /// <param name="message"></param>
    public override void ProcessMessage(SoapMessage message)
    {
        switch (message.Stage)
        {
            case SoapMessageStage.BeforeSerialize:
                break;
            case SoapMessageStage.AfterSerialize:
                xmlRequest = GetSoapEnvelope(newStream);
                CopyStream(newStream, oldStream);
                break;
            case SoapMessageStage.BeforeDeserialize:
                CopyStream(oldStream, newStream);
                xmlResponse = GetSoapEnvelope(newStream);
                break;
            case SoapMessageStage.AfterDeserialize:
                break;
        }
    }

    /// <summary>
    /// Returns the XML representation of the Soap Envelope in the supplied stream.
    /// Resets the position of stream to zero.
    /// </summary>
    /// <param name="stream"></param>
    /// <returns></returns>
    private XmlDocument GetSoapEnvelope(Stream stream)
    {
        var xml = new XmlDocument();
        stream.Position = 0;
        var reader = new StreamReader(stream);
        xml.LoadXml(reader.ReadToEnd());
        stream.Position = 0;
        return xml;
    }

    /// <summary>
    /// Copies a stream.
    /// </summary>
    /// <param name="from"></param>
    /// <param name="to"></param>
    private void CopyStream(Stream from, Stream to)
    {
        TextReader reader = new StreamReader(from);
        TextWriter writer = new StreamWriter(to);
        writer.WriteLine(reader.ReadToEnd());
        writer.Flush();
    }


    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="methodInfo"></param>
    /// <param name="attribute"></param>
    /// <returns></returns>
    public override object GetInitializer(LogicalMethodInfo methodInfo,
                                          SoapExtensionAttribute attribute)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="WebServiceType"></param>
    /// <returns></returns>
    public override object GetInitializer(Type WebServiceType)
    {
        return null;
    }

    /// <summary>
    /// Included only because it must be implemented.
    /// </summary>
    /// <param name="initializer"></param>
    public override void Initialize(object initializer)
    {
    }


}

Then you need to register the extension:

RegisterSoapExtension(typeof(TraceExtension), 1, 0);

Finally, after your requests/responses are done, you need to save the XML:

TraceExtension.XmlRequest.Save(@"c:\temp\ForwardRequest.xml");
TraceExtension.XmlResponse.Save(@"c:\temp\ForwardResponse{0}.xml");

Warning: this is actually pretty much what I used to pass through UPS certification, but this code has only been used once. As such, it may not be of the greatest quality, be pretty or otherwise very usable other than for that one single thing.



回答2:

For those who struggle like I did, if you are getting Null for both Request and Respose, need to register the extension before instantiating the ShipService.

TraceExtension.RegisterSoapExtension( typeof( TraceExtension ), 1, 0 ); ShipService shpSvc = new ShipService();

Hope this help someone :)



标签: .net xml api ups