A step by step guide to consuming a web service

by Heathesh 31. May 2011 00:35

I was recently asked for some help from a web developer on how to consume a service, specifically a web service that returns weather information. I thought this would be the perfect opportunity for a new blog post, seeing as I haven't posted in quite a while.

Using Visual Studio 2010, I create a new "Project", specifically an ASP.Net Web Application. I called it "WeatherServiceWebApplication". Next I want to add a reference to my web service. To do this:

1. Right click on "References" and select "Add Service Reference".
2. When the dialog pop's select, select the "Advanced" button on the bottom left hand side of the dialog.
3. Next select the "Add Web Reference" button on the bottom left hand side of the next dialog.
4. Paste the URL of the web service you wish to connect to in the "URL" textbox of the next dialog, in this case I'm connecting to http://iservice.co.za/WeatherInfo.asmx. Then hit enter.
5. I like to change my "Web Reference Name" which you'll find towards the bottom right of the dialog, I changed this to "iServiceWeather".
6. Then click the "Add Reference" button.

Once you've done that, you'll notice a new folder in your solution called "Web References" with the relevant web service reference within it. To do a simple implementation of this, I'm going to make it load some stuff in the default.aspx page.

To begin with, I can see from visiting http://iservice.co.za/WeatherInfo.asmx that there are two methods available on this web service. I'm going to use the GetSACityWeather call to get the weather for Johannesburg. By clicking on the "GetSACityWeather" method name on the previously mentioned URL, I get to see the method definition etc. I specifically want to know what this method call returns, and on this page (http://iservice.co.za/WeatherInfo.asmx?op=GetSACityWeather) I can see the following:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetSACityWeatherResponse xmlns="http://iservice.co.za/">
      <GetSACityWeatherResult>
        <City>string</City>
        <ForecastDate>dateTime</ForecastDate>
        <CurrentCondition>
          <Condition>string</Condition>
          <FahrenheitTemparature>double</FahrenheitTemparature>
          <CelciusTemparature>double</CelciusTemparature>
          <Humidity>string</Humidity>
          <WeatherIconUrl>string</WeatherIconUrl>
          <WindCondition>string</WindCondition>
        </CurrentCondition>
        <ForecastConditions>
          <ForecastCondition>
            <DayOfWeek>Sunday or Monday or Tuesday or Wednesday or Thursday or Friday or Saturday</DayOfWeek>
            <FahrenheitLowTemp>double</FahrenheitLowTemp>
            <FahrenheitHighTemp>double</FahrenheitHighTemp>
            <CelciusLowTemp>double</CelciusLowTemp>
            <CelciusHighTemp>double</CelciusHighTemp>
            <Condition>string</Condition>
            <WeatherIconUrl>string</WeatherIconUrl>
          </ForecastCondition>
          <ForecastCondition>
            <DayOfWeek>Sunday or Monday or Tuesday or Wednesday or Thursday or Friday or Saturday</DayOfWeek>
            <FahrenheitLowTemp>double</FahrenheitLowTemp>
            <FahrenheitHighTemp>double</FahrenheitHighTemp>
            <CelciusLowTemp>double</CelciusLowTemp>
            <CelciusHighTemp>double</CelciusHighTemp>
            <Condition>string</Condition>
            <WeatherIconUrl>string</WeatherIconUrl>
          </ForecastCondition>
        </ForecastConditions>
      </GetSACityWeatherResult>
    </GetSACityWeatherResponse>
  </soap:Body>
</soap:Envelope>


This tells me the response from the service call returns the object specified above, with all the relevant properties etc. available in the XML. So I want to add a few Literals to my default.aspx that I'll populate using this data. So I added the following:

    <p>
        <strong>City:</strong><asp:Literal ID="LiteralCity" runat="server" /></p>
    <p>
        <strong>ForecastDate:</strong><asp:Literal ID="LiteralForecastDate" runat="server" /></p>
    <p>
        <strong>CelciusTemparature:</strong><asp:Literal ID="LiteralCelciusTemparature" runat="server" /></p>



Then I added the following using to the code behind page of my default.aspx:

//WeatherServiceWebApplication is the name of my application and iServiceWeather is the name I gave the service
using WeatherServiceWebApplication.iServiceWeather;

Next, I added properties in my code behind for the Literals I've created on the form:

        /// <summary>
        /// Gets or sets the display city
        /// </summary>
        private string _displayCity
        {
            get { return LiteralCity.Text; }
            set { LiteralCity.Text = value; }
        }

        /// <summary>
        /// Gets or sets the display forecast date
        /// </summary>
        private string _displayForecastDate
        {
            get { return LiteralForecastDate.Text; }
            set { LiteralForecastDate.Text = value; }
        }

        /// <summary>
        /// Gets or sets the display celcius temparature
        /// </summary>
        private string _displayCelciusTemparature
        {
            get { return LiteralCelciusTemparature.Text; }
            set { LiteralCelciusTemparature.Text = value; }
        }


These I put above my Page_Load method, which I then change to:

        /// <summary>
        /// Handles the page load event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            //the iServicecozaWeatherInfo class is created by Visual Studio when it generates the web service reference
            using (iServicecozaWeatherInfo service = new iServicecozaWeatherInfo())
            {
                Weather weather = service.GetSACityWeather(Region.Gauteng, "Johannesburg");
                _displayCity = weather.City;
                _displayForecastDate = weather.ForecastDate.ToString("dd MMMMM yyyy");
                _displayCelciusTemparature = Convert.ToString(weather.CurrentCondition.CelciusTemparature);
            }
        }


That's it. When I run my little web application it will show the following on my web form:

    City:Johannesburg, GP

    ForecastDate:31 May 2011

    CelciusTemparature:9


Happy Servicing!

Tags:

Development | .Net | Visual Studio 2010 | Web Services

Run a single-threaded apartment method with parameters that returns a value within a web service

by Heathesh 21. July 2010 20:22

The need arose for me to run a method that used the WebBrowser object within a web service. The problem that I had is that you cannot run a WebBrowser object unless it's run in a single-threaded apartment. Within a windows forms or console application it's easy enough to set the apartment state by decorating your method with the [STAThread] attribute or using:

//set the current thread's apartment state
Thread.CurrentThread.SetApartmentState(ApartmentState.STA);


That does not work within a web service. My method also needed to accept parameters and to return a value. The method I needed to run looked like this:

public static byte[] GenerateScreenshot(string url, CustomImageFormat imageFormat, int width, int height)

This method was contained within a manager class I had created called GraphicsManager. As you can see it returns a byte[] and needs to accept four parameters. To call this method from the web service I first created a static private variable (make sure you create static variables) in my web service class for each of the parameters as well as the byte array like so:

        /// <summary>
        /// The returned image
        /// </summary>
        private static byte[] _returnedImage = null;
        /// <summary>
        /// The url
        /// </summary>
        private static string _url = string.Empty;
        /// <summary>
        /// The custom image format
        /// </summary>
        private static CustomImageFormat _imageFormat = CustomImageFormat.Gif;
        /// <summary>
        /// The width
        /// </summary>
        private static int _width = -1;
        /// <summary>
        /// The height
        /// </summary>
        private static int _height = -1;


I set default values for the variables simply out of habit. Next I created a single-threaded apartment method to execute my manager method like so. Notice that I decorated the method with the [STAThread] attribute and that the method is also a static method:

        /// <summary>
        /// Static method to run under Apartment State
        /// </summary>
        [STAThread]
        private static void generateScreenShot()
        {
            _returnedImage = GraphicsManager.GenerateScreenshot(_url, _imageFormat, _width, _height);
        }


As you can see I'm using the private variables I setup above in call to GraphicsManager.GenerateScreenshot. The last thing I needed to do was to create the WebMethod on my web service itself. I did this like so:

        /// <summary>
        /// Generates a portion of a screen shot image of the URL specified with with width and height specified and returns the byte stream of it in the specified format
        /// </summary>
        /// <param name="url">String of the URL to thumb nail</param>
        /// <param name="imageFormat">CustomImageFormat enum of the image format to return</param>
        /// <param name="width">Int of the width of the image to be returned</param>
        /// <param name="height">Int of the height of the image to be returned</param>
        /// <returns>Byte array of the thumb nail in the CustomImageFormat specified</returns>
        [WebMethod(Description = @"Generates a portion of a screen shot image of the URL specified with with width and height specified and returns the byte stream of it in the specified format.")]
        public byte[] GenerateWebsiteScreenshot(string url, CustomImageFormat imageFormat, int width, int height)
        {
            //set the private property values to the values passed in
            _url = url;
            _imageFormat = imageFormat;
            _width = width;
            _height = height;

            Thread apartmentThread = new Thread(new ThreadStart(generateScreenShot));

            //set the apartment state to single-threaded apartment
            apartmentThread.SetApartmentState(ApartmentState.STA);
            apartmentThread.Start();

            //block the calling thread so as to wait for the method to complete processing
            apartmentThread.Join();

            //return the private property value that was generated in the apartment state thread
            return _returnedImage;
        }


That was it. My web service method could now run and utilize the web browser object with no problems...

Happy threading!

Tags: , , ,

.Net | Web Services

Calling or using a web service method with parameters as a data source for a report

by Heathesh 21. July 2010 03:11

Using Visual Studio 2008, I came across an interesting problem a couple of developers were having trying to call a web service method with parameters and use it as a data source for a report. I actually found it's quite a finicky thing to do, but is relatively easy.

To begin with, I created a web service with a single method as a sample. My web service contained a method called GetPerson which expected a int parameter called id which would return a person object for the specified id.

Next I added a new report to a Visual Studio 2008 reports project I had already setup. Using the Report Wizard I specified the datasource type as XML, and added the URL of the web service as my connection string. You might have to click on "Credentials" and select "Use windows authententication" if you have a problem moving to the next window.

You should be presented with the "Design the Query" window next. Here click on the "Query Builder" button. Copy and paste the following text into your Query Designer:

<Query>
   <SoapAction>http://heathesh.com/ReportService/DataService/1.0/GetPerson</SoapAction>
   <Method Name="GetPerson" Namespace="http://heathesh.com/ReportService/DataService/1.0/">
   <Parameters>
       <Parameter Name="id">
           <DefaultValue>1</DefaultValue>
       </Parameter>
   </Parameters>
   </Method>
   <ElementPath IgnoreNamespaces="true">*</ElementPath>
</Query>


Things you have to change.

To start off with change the <SoapAction>. Access the web service using your browser e.g. go to "http://localhost/ReportWebService/DataService.asmx" and click on the method you're trying to run. In the description of the service you should see the name of the SoapAction you should use:

SOAP 1.1
The following is a sample SOAP 1.1 request and response. The placeholders shown need to be replaced with actual values.

POST /ReportWebService/DataService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://heathesh.com/ReportService/DataService/1.0/GetPerson"


Use the above mentioned SoapAction as specified above in the query:

   <SoapAction>http://heathesh.com/ReportService/DataService/1.0/GetPerson</SoapAction>

Next you need to specify the method name and namespace. The method name should be simple enough, but be careful to include any trailing slashes "/" in the namespace should they be required (take note of the trailing slash at the end of my namespace):

   <Method Name="GetPerson" Namespace="http://heathesh.com/ReportService/DataService/1.0/">

Next change the Parameter info as required. Please remember Parameter names are case sensitive and should be specified exactly the same as in your WSDL of your web service. Also I recommend always specifying a default value that will return data, this makes it easier for you to check that your method is executing properly from within your query designer (click on the exclamation mark "!" to run the query).

   <Parameters>
       <Parameter Name="id">
           <DefaultValue>1</DefaultValue>
       </Parameter>
   </Parameters>


The rest of the query should be left as is. Now that you've got your query setup, you can continue through the wizard setting up the other features of your report until your report has been created.

Adding the report parameters

The next step is to create report parameters that map to your web service method parameters. To do this open the "Report Data" window on the left. This window should appear next to your "Toolbox" and "Server Explorer" windows on the left of your Visual Studio IDE. Once the window is open, right click Parameters and select "Add new parameter". Give the parameter a relevant name etc. and set the data type to the relevant data type of the parameter of your web service and click "Okay".

Next right click the DataSet you created in the "Report Data" window (which is the web service dataset) and select "Dataset Properties". Click on "Parameters" in the window that opens and then "Add". Set the parameter name to the name of the parameter on the webservice method, for example my method needs a parameter called "id" so that's the name I used and in the drop down for the parameter value select the report parameter you created above then click "Okay".

Alright, that should be it. Select preview to view your report and you should be able to enter a parameter value and select "View Report" to view your report...

Happy Reporting!

 



Powered by BlogEngine.NET 1.5.0.7 (with enhancements by Heathesh)
Theme by Mads Kristensen (with tweeks by Heathesh)

Certifications

Microsoft Certified Professional

Microsoft Certified Technology Specialist

Answer Questions

 

Calendar

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar

http://heathesh.com