REST API: Create Deployment throwing error BadRequest (The specified configuration settings for Settings are invalid. Verify that the service configuration file is a valid XML file, and that role instance counts are specified as positive integers.)

Discussão Geral REST API: Create Deployment throwing error BadRequest (The specified configuration settings for Settings are invalid. Verify that the service configuration file is a valid XML file, and that role instance counts are specified as positive integers.)

  • terça-feira, 24 de julho de 2012 05:11
     
      Contém Código

    Hi All,

    We are trying to access the Create Deployment method stated below

    http://msdn.microsoft.com/en-us/library/windowsazure/ee460813

    We have uploaded the Package in the blob and browsing the configuration file. We have checked trying to upload manually the package and config file in Azure portal and its working fine.

    Below is the code we have written for creating deployment where "AzureEcoystemCloudService" is our cloud service name where we want to deploy our package. I have also highlighted the XML creation part.

    byte[] bytes = new byte[fupldConfig.PostedFile.ContentLength + 1];

                fupldConfig.PostedFile.InputStream.Read(bytes, 0, bytes.Length);

                string a = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                string base64ConfigurationFile = a.ToBase64();

                X509Certificate2 certificate = CertificateUtility.GetStoreCertificate(ConfigurationManager.AppSettings["thumbprint"].ToString());

    HostedService.CreateNewDeployment(certificate, ConfigurationManager.AppSettings["SubscriptionId"].ToString(), "2012-03-01", "AzureEcoystemCloudService", Infosys.AzureEcosystem.Entities.Enums.DeploymentSlot.staging,

                "AzureEcoystemDeployment", "http://shubhendustorage.blob.core.windows.net/shubhendustorage/Infosys.AzureEcoystem.Web.cspkg", "AzureEcoystemDeployment", base64ConfigurationFile, true, false);   

     /// <summary>

            ///

            /// </summary>

            /// <param name="certificate"></param>

            /// <param name="subscriptionId"></param>

            /// <param name="version"></param>

            /// <param name="serviceName"></param>

            /// <param name="deploymentSlot"></param>

            /// <param name="name"></param>

            /// <param name="packageUrl"></param>

            /// <param name="label"></param>

            /// <param name="base64Configuration"></param>

            /// <param name="startDeployment"></param>

            /// <param name="treatWarningsAsError"></param>

            public static void CreateNewDeployment(X509Certificate2 certificate, string subscriptionId,

                string version, string serviceName, Infosys.AzureEcosystem.Entities.Enums.DeploymentSlot deploymentSlot, string name, string packageUrl, string label, string base64Configuration,

                bool startDeployment, bool treatWarningsAsError)

            {

                Uri uri = new Uri(String.Format(Constants.CreateDeploymentUrlTemplate, subscriptionId, serviceName, deploymentSlot.ToString()));

                XNamespace wa = Constants.xmlNamespace;

                XDocument requestBody = new XDocument();

              

                String base64ConfigurationFile = base64Configuration;

                String base64Label = label.ToBase64();

                XElement xName = new XElement(wa + "Name", name);

                XElement xPackageUrl = new XElement(wa + "PackageUrl", packageUrl);

                XElement xLabel = new XElement(wa + "Label", base64Label);

                XElement xConfiguration = new XElement(wa + "Configuration", base64ConfigurationFile);

                XElement xStartDeployment = new XElement(wa + "StartDeployment", startDeployment.ToString().ToLower());

                XElement xTreatWarningsAsError = new XElement(wa + "TreatWarningsAsError", treatWarningsAsError.ToString().ToLower());

                XElement createDeployment = new XElement(wa + "CreateDeployment");

                

                createDeployment.Add(xName);

                createDeployment.Add(xPackageUrl);

                createDeployment.Add(xLabel);

                createDeployment.Add(xConfiguration);

                createDeployment.Add(xStartDeployment);

                createDeployment.Add(xTreatWarningsAsError);

                requestBody.Add(createDeployment);

                requestBody.Declaration = new XDeclaration("1.0", "UTF-8", "no");

                XDocument responseBody;

                RestApiUtility.InvokeRequest(

                    uri, Infosys.AzureEcosystem.Entities.Enums.RequestMethod.POST.ToString(), HttpStatusCode.Accepted, requestBody, certificate, version, out responseBody);

            }

    /// <summary>

            /// A helper function to invoke a Service Management REST API operation.

            /// Throws an ApplicationException on unexpected status code results.

            /// </summary>

            /// <param name="uri">The URI of the operation to invoke using a web request.</param>

            /// <param name="method">The method of the web request, GET, PUT, POST, or DELETE.</param>

            /// <param name="expectedCode">The expected status code.</param>

            /// <param name="requestBody">The XML body to send with the web request. Use null to send no request body.</param>

            /// <param name="responseBody">The XML body returned by the request, if any.</param>

            /// <returns>The requestId returned by the operation.</returns>

            public static string InvokeRequest(

                Uri uri,

                string method,

                HttpStatusCode expectedCode,

                XDocument requestBody,

                X509Certificate2 certificate,

                string version,

                out XDocument responseBody)

            {

                responseBody = null;

                string requestId = String.Empty;

                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);

                request.Method = method;

                request.Headers.Add("x-ms-Version", version);

                request.ClientCertificates.Add(certificate);

                request.ContentType = "application/xml";

                if (requestBody != null)

                {

                    using (Stream requestStream = request.GetRequestStream())

                    {

                        using (StreamWriter streamWriter = new StreamWriter(

                            requestStream, System.Text.UTF8Encoding.UTF8))

                        {

                            requestBody.Save(streamWriter, SaveOptions.DisableFormatting);

                        }

                    }

                }

                HttpWebResponse response;

                HttpStatusCode statusCode = HttpStatusCode.Unused;

                try

                {

                    response = (HttpWebResponse)request.GetResponse();

                }

                catch (WebException ex)

                {

                    // GetResponse throws a WebException for 4XX and 5XX status codes

                    response = (HttpWebResponse)ex.Response;

                }

                try

                {

                    statusCode = response.StatusCode;

                    if (response.ContentLength > 0)

                    {

                        using (XmlReader reader = XmlReader.Create(response.GetResponseStream()))

                        {

                            responseBody = XDocument.Load(reader);

                        }

                    }

                    if (response.Headers != null)

                    {

                        requestId = response.Headers["x-ms-request-id"];

                    }

                }

                finally

                {

                    response.Close();

                }

                if (!statusCode.Equals(expectedCode))

                {

                    throw new ApplicationException(string.Format(

                        "Call to {0} returned an error:{1}Status Code: {2} ({3}):{1}{4}",

                        uri.ToString(),

                        Environment.NewLine,

                        (int)statusCode,

                        statusCode,

                        responseBody.ToString(SaveOptions.OmitDuplicateNamespaces)));

                }

                return requestId;

            }

    But every time we are getting the below error from the line

     response = (HttpWebResponse)request.GetResponse();

    <Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Code>BadRequest</Code>
      <Message>The specified configuration settings for Settings are invalid. Verify that the service configuration file is a valid XML file, and that role instance counts are specified as positive integers.</Message>
    </Error>

     Any help is appreciated.

    Thanks,

    Shubhendu


    • Editado ShubhenduG terça-feira, 24 de julho de 2012 07:36 Hilighted some points
    • Tipo Alterado ShubhenduG terça-feira, 24 de julho de 2012 09:49 Changing type
    •  

Todas as Respostas

  • terça-feira, 24 de julho de 2012 05:49
     
      Contém Código

    Just a wild guess, but I noticed "byte[] bytes = new byte[fupldConfig.PostedFile.ContentLength + 1];", which means your array is one byte too big. I'm not sure that extra byte (probably initialized as a zero?) would cause XML validation to fail, but it's possible. I'd try fixing that before anything else.

    Also, you're reading in the bytes but then parsing them as UTF8 and then converting them back to (base64-encoded) bytes. I wonder if you should just convert the bytes directly, like this:

    byte[] bytes = new byte[fupldConfig.PostedFile.ContentLength];
    
    fupldConfig.PostedFile.InputStream.Read(bytes, 0, bytes.Length);
    
    string base64ConfigurationFile = Convert.ToBase64String(bytes);


    • Editado Steve Marx terça-feira, 24 de julho de 2012 05:52 missed a property
    •  
  • terça-feira, 24 de julho de 2012 05:51
     
     

    Can you do a quick check of your configuration file? Write the stream that you are adding to request in to a file and compare your original config and the one generated from code!

    Probably some special characters or something might be causing the issues. do a binary comparision if possible.


    Veerendra Balla

  • terça-feira, 24 de julho de 2012 05:52
     
      Contém Código

    Something like this is probably even nicer, but I'm less sure about this code:

    var ms = new MemoryStream(fupldConfig.PostedFile.ContentLength);
    
    fupldConfig.PostedFile.InputStream.CopyTo(ms);
    
    var base64ConfigurationFile = Convert.ToBase64String(ms.GetBuffer());


  • terça-feira, 24 de julho de 2012 05:56
     
     
    Yes, Steve mentioned a good point. I also believe you need to convert bytes directly to base64 string instead of parsing them to UFT8.

    Veerendra Balla

  • terça-feira, 24 de julho de 2012 07:29
    Usuário que responde
     
     
    I suspect Steve is right. The rest of the code looks pretty much like the code from my book.  Veerendra suggests you save a copy of the configuration file to validate against what you started with. This is good advice given the difficulty of debugging when going against the REST API. It might also be worth deploying everything using the portal just to make sure the package and configuration file are deployable.
  • terça-feira, 24 de julho de 2012 07:45
     
     

    I have used

    var ms = new MemoryStream(fupldConfig.PostedFile.ContentLength);

    fupldConfig.PostedFile.InputStream.CopyTo(ms);

    var base64ConfigurationFile = Convert.ToBase64String(ms.GetBuffer());

    instead of

    byte[] bytes = new byte[fupldConfig.PostedFile.ContentLength + 1];

                fupldConfig.PostedFile.InputStream.Read(bytes, 0, bytes.Length);

                string a = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                string base64ConfigurationFile = a.ToBase64();

    But still I am getting the same below error...

    <Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Code>BadRequest</Code>
      <Message>The specified configuration settings for Settings are invalid. Verify that the service configuration file is a valid XML file, and that role instance counts are specified as positive integers.</Message>
    </Error>

    Please help me


    Shubhendu G

  • terça-feira, 24 de julho de 2012 07:47
     
     

    We have already checked trying to upload manually the package and config file in Azure portal and its working fine.

    Please suggest what can be the reason of this error


    Shubhendu G

  • terça-feira, 24 de julho de 2012 08:20
     
     

    Please find the request XML I have found it in debug mode

    <CreateDeployment xmlns="http://schemas.microsoft.com/windowsazure">
      <Name>742d0a5e-2a5d-4bd0-b4ac-dc9fa0d69610</Name>
      <PackageUrl>http://shubhendustorage.blob.core.windows.net/shubhendustorage/WindowsAzure1.cspkg</PackageUrl>
      <Label>QXp1cmVFY295c3RlbURlcGxveW1lbnQ=</Label>
      <Configuration>77u/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0NCiAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KDQogIFRoaXMgZmlsZSB3YXMgZ2VuZXJhdGVkIGJ5IGEgdG9vbCBmcm9tIHRoZSBwcm9qZWN0IGZpbGU6IFNlcnZpY2VDb25maWd1cmF0aW9uLkNsb3VkLmNzY2ZnDQoNCiAgQ2hhbmdlcyB0byB0aGlzIGZpbGUgbWF5IGNhdXNlIGluY29ycmVjdCBiZWhhdmlvciBhbmQgd2lsbCBiZSBsb3N0IGlmIHRoZSBmaWxlIGlzIHJlZ2VuZXJhdGVkLg0KDQogICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi0tPg0KPFNlcnZpY2VDb25maWd1cmF0aW9uIHNlcnZpY2VOYW1lPSJXaW5kb3dzQXp1cmUxIiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS9TZXJ2aWNlSG9zdGluZy8yMDA4LzEwL1NlcnZpY2VDb25maWd1cmF0aW9uIiBvc0ZhbWlseT0iMSIgb3NWZXJzaW9uPSIqIiBzY2hlbWFWZXJzaW9uPSIyMDEyLTA1LjEuNyI+DQogIDxSb2xlIG5hbWU9IldlYlJvbGUxIj4NCiAgICA8SW5zdGFuY2VzIGNvdW50PSIyIiAvPg0KICAgIDxDb25maWd1cmF0aW9uU2V0dGluZ3M+DQogICAgICA8U2V0dGluZyBuYW1lPSJNaWNyb3NvZnQuV2luZG93c0F6dXJlLlBsdWdpbnMuRGlhZ25vc3RpY3MuQ29ubmVjdGlvblN0cmluZyIgdmFsdWU9IkRlZmF1bHRFbmRwb2ludHNQcm90b2NvbD1odHRwcztBY2NvdW50TmFtZT1zaHViaGVuZHVzdG9yYWdlO0FjY291bnRLZXk9WHIzZ3o2aUxFSkdMRHJBd1dTV3VIaUt3UklXbkFrYWo0MkFEcU5saGRKTTJwUnhnSzl4TWZEcTQ1ZHI3aDJXWUYvYUxObENnZ0FiZnhONWVBZ2lTWGc9PSIgLz4NCiAgICA8L0NvbmZpZ3VyYXRpb25TZXR0aW5ncz4NCiAgPC9Sb2xlPg0KPC9TZXJ2aWNlQ29uZmlndXJhdGlvbj4=</Configuration>
      <StartDeployment>true</StartDeployment>
      <TreatWarningsAsError>false</TreatWarningsAsError>
    </CreateDeployment>


    Shubhendu G

  • terça-feira, 24 de julho de 2012 08:21
     
     

    I have used

    var ms = new MemoryStream(fupldConfig.PostedFile.ContentLength);

    fupldConfig.PostedFile.InputStream.CopyTo(ms);

    var base64ConfigurationFile = Convert.ToBase64String(ms.GetBuffer());

    instead of

    byte[] bytes = new byte[fupldConfig.PostedFile.ContentLength + 1];

                fupldConfig.PostedFile.InputStream.Read(bytes, 0, bytes.Length);

                string a = Encoding.UTF8.GetString(bytes, 0, bytes.Length);

                string base64ConfigurationFile = a.ToBase64();

    But still I am getting the same below error...

    <Error xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      <Code>BadRequest</Code>
      <Message>The specified configuration settings for Settings are invalid. Verify that the service configuration file is a valid XML file, and that role instance counts are specified as positive integers.</Message>
    </Error>

    Please help me


    Shubhendu G

  • terça-feira, 24 de julho de 2012 08:23
     
     

    Hi Neil,

    We have checked trying to upload manually the package and config file in Azure portal and its working fine but through REST API its giving the error

    Thanks,

    Shubhendu


    Shubhendu G

  • terça-feira, 24 de julho de 2012 10:33
     
     

    Try this : Have highlighted the changes

                    

                    byte[] bytes = new byte[FileUpload1.PostedFile.ContentLength + 1];
                    
                    XmlDocument myDoc = new XmlDocument();                
                    myDoc.Load(FileUpload1.FileContent);
                    string base64ConfigurationFile = myDoc.InnerXml.ToBase64();
                    X509Certificate2 certificate =
                        GetStoreCertificate("370298064A205C22BCF5FDFB0FDE139B29957E1A");

                    CreateNewDeployment(......);
                }

  • terça-feira, 24 de julho de 2012 13:46
     
     

    I reverse engineered your configuration file (You may want to change your account key now :)) and found out that there was an extra character in the beginning of your XML document (see the "?" sign just before <?xml> declaration). This is what I got:

    ===============================================================

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

      This file was generated by a tool from the project file: ServiceConfiguration.Cloud.cscfg

      Changes to this file may cause incorrect behavior and will be lost if the file is regenerated.

      **********************************************************************************************
    -->
    <ServiceConfiguration serviceName="WindowsAzure1" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="1" osVersion="*" schemaVersion="2012-05.1.7">
      <Role name="WebRole1">
        <Instances count="2" />
        <ConfigurationSettings>
          <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="DefaultEndpointsProtocol=https;AccountName=shubhendustorage;AccountKey=your account key" />
        </ConfigurationSettings>
      </Role>
    </ServiceConfiguration>

    ========================================================

    It seems it is getting corrupted during upload. Can you try hard coding the config file contents in your code and then creating deployment? That way you will be sure that there are no issues with Service Management API portion of your code.

    Hope this helps.

    Thanks

    Gaurav


  • terça-feira, 24 de julho de 2012 17:52
     
      Contém Código

    The extra character is probably a byte-order mark. Okay, I'm now going to suggest the opposite of what I suggested earlier. :-) Looking at some code of mine, I see that I'm converting the .cscfg to ASCII before uploading, so give this a try?

    string base64ConfigurationFile;
    
    using (var r = new StreamReader(fupldConfig.PostedFile.InputStream))
    {
        base64ConfigurationFile = Convert.ToBase64String(Encoding.ASCII.GetBytes(r.ReadToEnd());
    }


  • terça-feira, 24 de julho de 2012 18:09
    Usuário que responde
     
      Contém Código

    Steve's latest suggestion is pretty close to the original source that the code is copied from except that I used UTF8 instead of ASCII, as in the following fragment:

    String configurationFile = File.ReadAllText(pathToConfigurationFile);
    String base64ConfigurationFile = ConvertToBase64String(configurationFile);
    
    private String ConvertToBase64String(String value)
    {
    	Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
    	String base64String = Convert.ToBase64String(bytes);
    	return base64String;
    }

  • terça-feira, 31 de julho de 2012 00:12
     
     

    I am trying to create the deployment as well and I am wondering how should I specify my Package URL?!

    I mean should I upload a package file in advance?! 


    Shaghayegh

  • terça-feira, 31 de julho de 2012 01:27
    Usuário que responde
     
     

    --  I am trying to create the deployment as well and I am wondering how should I specify my Package URL?!

    You should specify the full URL for the package. It needs to be in a storage account under the subscription, or include a shared access signature. You should upload the package in advance. Note that the configuration file must be on the local file system

  • quarta-feira, 1 de agosto de 2012 08:00
     
     

    Hi Neil,ShubhenduG

    Need urgent help.

    I am also trying to create a deployment through API. I need to specify package url. As you suggested it should be under storage account. How can I upload that package to the storage account.Also can one storage account have more than one package associated with them?

    ShubhenduG, Let me know how you uploaded package that you mentioned in your request.

    Thanks both in advance.

  • quarta-feira, 1 de agosto de 2012 08:34
     
     

    There are a number of storage explorers available in the market (open source, free, commercial). You can use any one of them to upload your package file in the blob storage. Then you can get the URL for that blob and specify it here.

    A package in blob storage is just another blob. You can have as many packages in blob storage as you like.

  • quarta-feira, 1 de agosto de 2012 08:42
     
     

    Hi,

    You can use any storage explorer tools to upload your package to your storage account. You can also write your own code to upload to your storage account.

    Download the storage explorer from code plex. And upload your package to your storage account. Once you upload take the blob URL and supply the same to your deployment package.

    To the question "Also can one storage account have more than one package associated with them?", yes you can have multiple packages associated with one account and each package will have its own BLOB URI.

    Here is the screenshot of storage explorer. In the screenshot you can see the blob URI. Also all the items you are seeing in the screenshots are deployment packages only.

    Please let me know for any other specific questions related to automating the deployment.



    Please mark the replies as Answered if they help and Vote if you found them helpful.

  • quarta-feira, 1 de agosto de 2012 15:20
    Usuário que responde
     
     
    Gaurav Mantri, who answered the question, developed a great Azure storage explorer tool called Cloud Storage Studio.
  • quinta-feira, 2 de agosto de 2012 10:58
     
     

    Thanks alot, I am using azure storage explorer to upload my package and it worked.

    I have another question, can we get status of deployment programmatically.I didn't find any API to get status , like running/stopped.

    I need to delete a deployment but before deleting it should be stopped , so want to check the status before deleting and accordingly take actions.

  • sexta-feira, 3 de agosto de 2012 02:30
    Usuário que responde
     
     

    -- I have another question, can we get status of deployment programmatically.I didn't find any API to get status , like running/stopped.

    Look at Get Hosted Service Properties with embed-detail = true.

  • sexta-feira, 3 de agosto de 2012 10:21
     
     
    Thanks a lot Neil. That worked :)
  • segunda-feira, 17 de setembro de 2012 13:01
     
     

    Hi..

    I want to add Environment variable in my csdef file. When I <Environment> element in my ServiceDefinition.csdef file, it's giving me error.

    Warning    1    The element 'VirtualMachineRole' in namespace 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition' has invalid child element 'Startup' in namespace 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition'. List of possible elements expected: 'Certificates, LocalResources, Endpoints, ConfigurationSettings' in namespace 'http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition'.    c:\users\administrator\documents\visual studio 2010\Projects\WindowsAzure6_Env\WindowsAzure6_Env\ServiceDefinition.csdef    7    6    WindowsAzure6_Env

    My File look like below

    <?xml version="1.0" encoding="utf-8"?>
    <ServiceDefinition name="WindowsAzure6_Env" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-05.1.7">
      <VirtualMachineRole name="VMRole1" vmsize="Small">
        <Imports>
          <Import moduleName="Diagnostics" />
        </Imports>
        <Startup>
               <Environment>
              <Variable name="MY_ENV" value="my_value" />
            </Environment>
         </Startup>
        <Runtime>
          <Environment>
            <Variable name="MY_SECOND_ENV" value="my_value2" />
          </Environment>
        </Runtime>
      </VirtualMachineRole>
    </ServiceDefinition>

    Please let me know if you have any solution.Thanks

        
  • segunda-feira, 17 de setembro de 2012 13:34
     
     

    Hi Veerendra

    I want to setup some Env variable unique to each VM at the time of creation of VM. I am creating VM programmtically using Rest API. Now can I set environment variable unique to each VM instance. I am creating various VM using same config file uploaded in my storage account. Is there any way to update env variable for each VM. Thanks in advance.

  • quarta-feira, 19 de setembro de 2012 16:08
     
     

    This seems like an unrelated question. Start a new thread.

    (But the short answer is that VM roles don't have startup tasks.)

  • quarta-feira, 7 de novembro de 2012 07:26
     
     

    There are two basic ways to do this.

    1. Use either StorageExplorer (Intermediate tool) to upload that file to blob under same subscription.

    2. Develop your own code to upload service package to blob. Probably you've to use Block Blobs for this, couse it's comparativly lage file