none
The remote server returned an error: (400) Bad Request

    Question

  • I have been putting together the option to update instance count based on this example by Neil Mackenzie. Though I run up into the problem where in my configuration update through POST fails with the message "The remote server returned an error: (400) Bad Request" This is the code where i write the configuration change private static String ChangeDeployment(WhiteSpiderConfiguration configuration) { String requestId = String.Empty; String uriString = "https://management.core.windows.net/subscriptionid/services/hostedservices/service_name/deploymentslots/staging/?comp=config"; Uri uri = new Uri(uriString); HttpWebRequest httpWebRequest = CreateHttpWebRequest(uri, "POST"); using (Stream requestStream = httpWebRequest.GetRequestStream()) { WriteChangeDeploymentRequest(requestStream, configuration); } using (HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse()) { requestId = response.Headers["x-ms-request-id"]; } return requestId; }
    Monday, May 23, 2011 5:27 AM

Answers

  • I would invoke the Get Deployment operation and load the response into an XDocument. I would then get the base-64 encoded configuration file from the Configuration element. I would use the code in my SQL Azure Management post to create the correct payload, using this base-64 encoded configuration file, with namespaces, etc. I would then invoke the Change Deployment Configuration operation.

    Things to watch for. You shouldn't use Fiddler when trying this out since the management certificate is not passed through and the request will fail. It is actually worth using just to ensure the request is correct but you should only do so in the knowledge that the request will subsequently fail. I believe there is also an issue about needing to ensure that different elements are on different lines in the XML payload. You should also ensure that you are using a valid version number.

    • Marked as answer by consoleart_ Tuesday, May 31, 2011 11:49 AM
    Wednesday, May 25, 2011 5:30 PM

All replies

  • Hi consoleart_,

    > I run up into the problem where in my configuration update through POST fails with the message "The remote server returned an error: (400) Bad Request".

    May I ask you for the WriteChangeDeploymentRequest method? I am not able to find this method from your given link, thus I failed to reproduce the issue.

    Also, may I ask you to ouput the raw request content before calling GetResponse method to sumit it? The request content will help us know if it is in correct format or not.

    Thanks,


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    Tuesday, May 24, 2011 4:05 AM
  • This is the Write deployment method

    public static void WriteChangeDeploymentRequest(Stream stream, WhiteSpiderConfiguration whiteSpiderConfiguration)
    {
    String configuration = whiteSpiderConfiguration.WriteXml();

    AzureServiceChangeConfiguration azureDeployment = new AzureServiceChangeConfiguration
    {
    Configuration = configuration,
    };

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(AzureServiceChangeConfiguration));
    xmlSerializer.Serialize(stream, azureDeployment);
    }

    and this is the other part of the code which throws up the error

    String requestId = String.Empty;
    String uriString = “https://management.core.windows.net/subscriptid/services/hostedservices/cygnusattacment/deployments/mydeploymentname/?comp=config”;
    Uri uri = new Uri(uriString);
    HttpWebRequest httpWebRequest = CreateHttpWebRequest(uri, “POST”);

    using (Stream requestStream = httpWebRequest.GetRequestStream())
    {
    WriteChangeDeploymentRequest(requestStream, configuration);
    }

    using (HttpWebResponse response =
    (HttpWebResponse)httpWebRequest.GetResponse())
    {
    requestId = response.Headers["x-ms-request-id"];
    }
    return requestId;

    It throws up error in the using (HttpWebResponse response =
    (HttpWebResponse)httpWebRequest.GetResponse())..saying its a “400: bad request”.

    Tuesday, May 24, 2011 4:53 AM
  • Hi consoleart,

    I am still not able to compile and reproduce the issue on my machine yet. Sorry. May I ask what the definition of AzureServiceChangeConfiguration class is?

    May I ask you to package your project (before packaging, please replace the subscription id and servie name with place holders) and upload it to Windows Live SkyDrive and share the link with us? This will be very helpful for investigating and solving this issue.

    Besides, to do troubleshooting by yourself, I'd suggest outputing the raw http request to a text file and comparing it with Change Deployment Configuration so that you can find out if the request content is in the correct format or not.

    private String ChangeDeployment(WhiteSpiderConfiguration configuration)
    {
        String requestId = String.Empty;
        String uriString = "https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y493YYX4757X/services/hostedservices/whitespider/deploymentslots/staging/?comp=config";
        Uri uri = new Uri(uriString);
        HttpWebRequest httpWebRequest = CreateHttpWebRequest(uri, "POST");

        using (Stream requestStream = httpWebRequest.GetRequestStream())
        {
            WriteChangeDeploymentRequest(requestStream, configuration);
        }

        StringBuilder builder = new StringBuilder();

        builder.AppendLine("Headers: \n");
        foreach (string key in httpWebRequest.Headers.Keys)
        {
            builder.AppendFormat("{0}: {1}\n", key, Request.Headers[key]);
        }

        StreamReader reader = new StreamReader(httpWebRequest.InputStream);
        string request = reader.ReadToEnd();

        builder.AppendLine("\nBody: \n");
        builder.AppendLine(request);

        File.WriteAllText("D:\\output.txt", builder.ToString());

        using (HttpWebResponse response =
                (HttpWebResponse)httpWebRequest.GetResponse())
        {
            requestId = response.Headers["x-ms-request-id"];
        }
        return requestId;
    }

    Thanks,


    Wengchao Zeng
    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework
    Tuesday, May 24, 2011 6:48 AM
  • This is the class file

     

        [XmlRootAttribute(ElementName = "ChangeConfiguration", Namespace = "http://schemas.microsoft.com/windowsazure")]

        public class AzureServiceChangeConfiguration : IXmlSerializable

        {

            public AzureServiceChangeConfiguration() { }

     

            public String Configuration

            {

                get;

                set;

            }

     

            public XmlSchema GetSchema()

            {

                return null;

            }

     

            public void ReadXml(XmlReader xmlReader)

            {

                System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();

     

                xmlReader.ReadStartElement();

     

                String base64Configuration = xmlReader.ReadElementContentAsString();

                Byte[] configurationData = System.Convert.FromBase64String(base64Configuration);

                Configuration = asciiEncoding.GetString(configurationData);

            }

     

            public void WriteXml(XmlWriter xmlWriter)

            {

                Byte[] configurationBytes = System.Text.Encoding.UTF8.GetBytes(Configuration);

     

                xmlWriter.WriteStartElement("Configuration");

                xmlWriter.WriteBase64(configurationBytes, 0, configurationBytes.Count<Byte>());

                xmlWriter.WriteEndElement();

            }

        }

    Wednesday, May 25, 2011 10:33 AM
  • this is the full file on skydrive

    http://cid-f9800a2b24162aa3.office.live.com/embedicon.aspx/.Documents/Program.cs

    also there is a USING at the top which needs to be removed...

    using Microsoft.Samples.WindowsAzure.ServiceManagement;

    • Edited by consoleart_ Wednesday, May 25, 2011 10:50 AM
    Wednesday, May 25, 2011 10:39 AM
  • I tried your code

     StringBuilder builder = new StringBuilder();

        builder.AppendLine("Headers: \n");
        foreach (string key in httpWebRequest.Headers.Keys)
        {
            builder.AppendFormat("{0}: {1}\n", key, Request.Headers[key]);
        }

        StreamReader reader = new StreamReader(httpWebRequest.InputStream);
        string request = reader.ReadToEnd();

        builder.AppendLine("\nBody: \n");
        builder.AppendLine(request);

        File.WriteAllText("D:\\output.txt", builder.ToString());

    The Request class was nto there - so changedtto httpWebRequest, and there is no InputStream in httpWebRequest

    Wednesday, May 25, 2011 10:50 AM
  • consoleart -

    You should use an XDocument to create the request body. I show an example of this in a post on the SQL Azure Management API which you is very similar to the Windows Azure Service Management REST API.

    As a first step I would actually issue a GET request to download the configuration into an XDocument and send the same configuration back without change. That proves I can download and upload a configuration. Only then would I move on to extracting the configuration from its base-64 version, changing it, re-econcoding it and uploading it.

    Wednesday, May 25, 2011 3:55 PM
  • hi i used the webrequest method.....this is what i use this URL

    https://management.core.windows.net/subscriptionid/services/hostedservices/name/deploymentslots/staging/?comp=config

    i get a forbidden error..but in another place to get the deployment i use the following url

    https://management.core.windows.net/subscriptionid/services/hostedservices/servicename/deploymentslots/staging

    and it works fine...here is the code that isuse to retrieve

                HttpWebRequest webRequest = CreateHttpWebRequest(uri, "GET");

     

                //=== No Request Payload needed to return server list ===//

     

                using (WebResponse webResponse = webRequest.GetResponse()) // error is thrown here...403: Forbidden error 

                {

                    //=== x-ms-request-id is useful for troubleshooting request failures with Microsoft ===//

                    Console.WriteLine("Response x-ms-request-id : {0}", webResponse.Headers["x-ms-request-id"]);

                    Console.WriteLine("HttpStatusCode = {0}\n", (int)((HttpWebResponse)webResponse).StatusCode);

     

                    using (Stream stream = webResponse.GetResponseStream())

                    {

                        using (StreamReader sr = new StreamReader(stream))

                        {

                            Console.WriteLine(sr.ReadToEnd());

                        }

                    }

                }

    Wednesday, May 25, 2011 5:11 PM
  • I would invoke the Get Deployment operation and load the response into an XDocument. I would then get the base-64 encoded configuration file from the Configuration element. I would use the code in my SQL Azure Management post to create the correct payload, using this base-64 encoded configuration file, with namespaces, etc. I would then invoke the Change Deployment Configuration operation.

    Things to watch for. You shouldn't use Fiddler when trying this out since the management certificate is not passed through and the request will fail. It is actually worth using just to ensure the request is correct but you should only do so in the knowledge that the request will subsequently fail. I believe there is also an issue about needing to ensure that different elements are on different lines in the XML payload. You should also ensure that you are using a valid version number.

    • Marked as answer by consoleart_ Tuesday, May 31, 2011 11:49 AM
    Wednesday, May 25, 2011 5:30 PM
  • I have got the configuration XML through GetDeployment ...but i am not able to invoke the change Deployment ...its throwing up the same errror...and i dont have my fiddler currently running.

    If possible point to some example where the change deployment is being used...thanks a lot..

    Wednesday, May 25, 2011 6:28 PM
  • This is my final script based using XDocument (based on the AutoScale ref http://cloud.dzone.com/news/windows-azure-and-scaling-how)

    but it still shows the same error "400 bad request the the request point...is it that iam missing with the link ?

     

            private const string ServiceEndpoint = "https://management.core.windows.net";

     

            private static Binding WebHttpBinding()

            {

                var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

                binding.ReaderQuotas.MaxStringContentLength = 67108864;

     

                return binding;

            }

     

            static void Main(string[] args)

            {

                // Some commercial info :-)

                Console.WriteLine("AutoScale - (c) 2011 Maarten Balliauw");

                Console.WriteLine("");

     

                // Quick-and-dirty argument check

                if (args.Length != 6)

                {

                    Console.WriteLine("Usage:");

                    Console.WriteLine("  AutoScale.exe <certificatefile> <subscriptionid> <servicename> <rolename> <slot> <instancecount>");

                    Console.WriteLine("");

                    Console.WriteLine("Example:");

                    Console.WriteLine("  AutoScale.exe mycert.cer 39f53bb4-752f-4b2c-a873-5ed94df029e2 bing Bing.Web production 20");

                    return;

                }

     

                // Save arguments to variables

                var certificateFile = args[0];

                var subscriptionId = args[1];

                var serviceName = args[2];

                var roleName = args[3];

                var slot = args[4];

                var instanceCount = args[5];

     

                // Do the magic

                var managementClient = Microsoft.Samples.WindowsAzure.ServiceManagement.ServiceManagementHelper.CreateServiceManagementChannel(

                    WebHttpBinding(), new Uri(ServiceEndpoint), GetX509Certificate2(""));

     

                Console.WriteLine("Retrieving current configuration...");

     

                var deployment = managementClient.GetDeploymentBySlot(subscriptionId, serviceName, slot);

                string configurationXml = ServiceManagementHelper.DecodeFromBase64String(deployment.Configuration);

     

                Console.WriteLine("Updating configuration value...");

     

                var serviceConfiguration = XDocument.Parse(configurationXml);

     

                serviceConfiguration

                        .Descendants()

                        .Single(d => d.Name.LocalName == "Role" && d.Attributes().Single(a => a.Name.LocalName == "name").Value == roleName)

                        .Elements()

                        .Single(e => e.Name.LocalName == "Instances")

                        .Attributes()

                        .Single(a => a.Name.LocalName == "count").Value = instanceCount;

     

                var changeConfigurationInput = new ChangeConfigurationInput();

                changeConfigurationInput.Configuration = ServiceManagementHelper.EncodeToBase64String(serviceConfiguration.ToString(SaveOptions.DisableFormatting));

     

                Console.WriteLine("Uploading new configuration...");

     

                managementClient.ChangeConfigurationBySlot(subscriptionId, serviceName, slot, changeConfigurationInput);//ERROR MESSAGE THROWS UP HERE

     

                Console.WriteLine("Finished.");

            }

            private static X509Certificate2 GetX509Certificate2(String subjectName)

            {

                X509Certificate2 x509Certificate2 = null;

                X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);

                try

                {

                    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

     

     

                    X509Certificate2Collection x509Certificate2Collection = store.Certificates.Find(X509FindType.FindByThumbprint, "8011E1BB408DD8B9277FC0696E93F171E1E43D52", false);

                    x509Certificate2 = x509Certificate2Collection[0];

     

     

                }

                finally

                {

                    store.Close();

                }

                return x509Certificate2;

            }

    Friday, May 27, 2011 6:41 AM
  • It seems the problem is with my Staging deployment, i move my deployment to production and the able to scale down my instance count...thnx... it appears that the REST API call is CASE SENSITIVE
    Tuesday, May 31, 2011 11:51 AM