View RSS Feed

richyrich

Convert .asmx file to WCF .svc file to create simple API web service

Rate this Entry
by on October 19th, 2009 at 10:01 PM (336 Views)
2) A simple .asmx file and calling a function

This is part of a series of blogs. The others are:-
1) Introduction
3) Converting a .asmx file to WCF .svc file

The .asmx file I started with probably isn’t a great example of something you’d want as a web service, but it was just something I was working on at the time and I think it’s complicated enough to enable you to develop a variety of different applicable WCF services. What I have is an asmx file that sends an email based on parameters passed to it; who it’s to, who it’s from, subject, message etc.

.asmx code behind
Code:
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 using System.Web.Services;
 //this next namespace is my own.It basically just contains a function to wire up an email and send it
 //It accepts an email class object as a parameter. This class just mirrors the iEmail class here.
 using mynamespace.App.BLL.Emails;

 ///<summary>
 /// Summary description for emailing
 ///</summary>
 [WebService(Namespace = "http://tempuri.org/")]
 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
 // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
 [System.Web.Script.Services.ScriptService]
 public class emailingService : System.Web.Services.WebService {

  public emailingService () {

  //Uncomment the following line if using designed components 
  //InitializeComponent(); 
     }
  //We have one simple function that accepts an emailTo, emailFrom, Subject and Message parameter
     [WebMethod(MessageName="SendEmailStr")]
  public response SendEmailStr(string loc, string emailTo, string emailFrom, string subject, string message)
     {
  response response = new response();
         response.loc = loc;

  email newEmail = new email();
         newEmail.emailTo.Add(new emailAdd(emailTo));
         newEmail.emailFrom.Add(new emailAdd(emailFrom));
         newEmail.subject = subject;
         newEmail.message = message;
         newEmail.priority = "Normal";
         newEmail.read = false;
         newEmail.filepath = "";

         newEmail.seperate = false;
         newEmail.isHTML = true;
         newEmail.sendAsync = false;

  if (!email.SendEmail(newEmail))
         {
             response.error = true;
             response.message = "An error occurred whilst sending the email<br />" + newEmail.err;
         }
  else
         {
             response.error = false;
             response.message = "Your email has been sent";
         }
  return response;
     }

  //And another function that accepts an iEmail object as a parameter
     [WebMethod(MessageName="SendEmailObj")]
  public response SendEmailObj(string loc, iEmail oEmail)
     {
  response response = new response();
         response.loc = loc;

  email newEmail = new email();
         newEmail.emailTo.Add(new emailAdd(oEmail.emailTo));
         newEmail.emailFrom.Add(new emailAdd(oEmail.emailFrom));
         newEmail.subject = oEmail.subject;
         newEmail.message = oEmail.message;
         newEmail.priority = oEmail.priority;
         newEmail.read = oEmail.read;
         newEmail.filepath = "";

         newEmail.seperate = false;
         newEmail.isHTML = true;
         newEmail.sendAsync = false;

  if (!email.SendEmail(newEmail))
         {
             response.error = true;
             response.message = "An error occurred whilst sending the email<br />" + newEmail.err;
         }
  else
         {
             response.error = false;
             response.message = "Your email has been sent";
         }
  return response;
     }

 }

 //This class will be exposed to our client once we wire up the web service to our page
 public class iEmail
 {
  public iEmail()
     {
     }

  public string emailTo { get; set; }
  public string emailFrom { get; set; }
  public string emailCc { get; set; }
  public string emailBcc { get; set; }
  public string subject { get; set; }
  public string message { get; set; }
  public string priority { get; set; }
  public bool read { get; set; }
  public bool own { get; set; }
  public string filepath { get; set; }

 }

 // A simple response class that will be returned to the client
 public class response
 {
  public bool error { get; set; } //boolean value to return if an error occurs or not
  public string loc { set; get; } //just enables the passing of the naming container that holds the various form objects
  public string message { get; set; } //a message to return to the client
 }
 

I guess you wouldn’t really want to expose an emailing function as a web service due to potential issues with spammers highjacking etc. I just used this as an example as it provides for a number of different scenarios with web services and Windows Communication Foundation (WCF) You would also validate the values received into the functions to ensure they were valid etc. prior to the email being sent, but this is just meant as a simple example.

Exposing the Web Service
To wire this up to your page you need to include a ScriptManager control in your page.
Code:
  <asp:ScriptManager id=”myScriptManager” runat=”server” EnablePartialRendering=”true” />
If you use a master page, what you can do is include this control in your master page and then expose a public function to allow you to include a service from your page code. Something like:-
Master Page
Code:
 public void setService(ServiceReferenceitem)
  {
     this.myScriptManager.Services.Add(item);
  }
 


Your .aspx Page
Code:
  void Page_PreRender()
     {
  ServiceReference service = new ServiceReference("/services/emailing.asmx");
         Master.setService(service);
     }
 

Once this is done, your web service is exposed to the client.


Consuming the web service
Suppose we had a page setup like this:-
email.aspx
Code:
 <div id="mainHolder" style="text-align: center; margin-left: auto; margin-right: auto;width: 100%; overflow: hidden;">
    <ul class="input-fields">
  <li>
           <asp:Label ID="lblEmailTo" runat="server" Text="To:" CssClass="blue336799_9" />
           <asp:TextBox ID="txtEmailTo" runat="server" CssClass="textbox8" style="color:#CCCCCC;" Width="200px" MaxLength="255" />
  </li>
  <li>
  <asp:Label ID="lblEmailFrom" runat="server" Text="From:" CssClass="blue336799_9" />
  <asp:TextBox ID="txtEmailFrom" runat="server" CssClass="textbox8" Width="200px" MaxLength="255" />
  </li>
  <li>
  <asp:Label ID="lblSubject" runat="server" Text="Subject:" CssClass="blue336799_9" />
  <asp:TextBox ID="txtSubject" runat="server" CssClass="textbox8" Width="200px" MaxLength="255" />
  </li>
  <li>
  <fckEditor:FCKeditor ID="txtMessage" runat="server" HtmlEncodeOutput="true" UseBROnCarriageReturn="true" ToolbarSet="myToolbar" BaseHref="http://www.mydomain.com" Height="350px" />
  </li>
  </ul>
  </div>
  <div id="optionsHolder" style="text-align: center; margin-left: auto; margin-right: auto; width: 100%; overflow: hidden;">
  <ul class="input-fields">
  <li>
  <asp:Label ID="lblImportance" runat="server" CssClass="blue336799_8" Text="Importance:" />
  <asp:DropDownList ID="ddlImportance" runat="server" CssClass="textbox8">
  <asp:ListItem Text="Normal" Value="normal" />
  <asp:ListItem Text="Low" Value="low" />
  <asp:ListItem Text="High" Value="high" />
  </asp:DropDownList>
  </li>
  <li>
  <asp:Label ID="lblReadReceipt" runat="server" CssClass="blue336799_8" Text="Read Receipt:" />
  <asp:CheckBox ID="chkReadReceipt" runat="server" />
  </li>
  <li>
  <asp:Label ID="lblOwn" runat="server" CssClass="blue336799_8" Text="Copy to own email:" />
  <asp:CheckBox ID="chkOwn" runat="server" />
  </li>
  </ul>
 </div>
 <div id="emailSendButton" class="center_button" style="padding-top: 10px;">
    <button id="btnEmailSend" class="button_25px_green" title="Send Email" onclick="return SendEmail('<%=this.txtEmailTo.NamingContainer.ClientID %>_');">Send Email</button>
 </div>
 

This is just the relevant form code. You’ll need to add the page declarations etc.

Code Behind (email.aspx.cs)
Code:
  void Page_PreRender()
     {
         //Add the service reference to our master page, as shown above
         //This assumes the .asmx file is in a sub folder of our webroot
         //called services
  ServiceReference service = new ServiceReference("/services/emailing.asmx");
         Master.set_services(service);
     }

  protected void Page_Load(object sender, EventArgs e)
     {
         //we also need to register our Javascript that will handle the calls to the webservice
         //This assumes the .js file is in a sub folder of our webroot
         //called js
         Page.ClientScript.RegisterClientScriptInclude("sendemail.js", "/js/sendemail.js");
     }
 

Our Javascript File
Code:
 //Function that is called by our button click. The parameter is the
 //naming container client id, which makes it easier to reference the
 //form elements
 function SendEmail(loc) {
  var email = new iEmail();
  var emailto = document.getElementById(loc + 'txtEmailTo').value;
     email.emailTo = emailto;
  var emailfrom = document.getElementById(loc + 'txtEmailFrom').value;
     email.emailFrom = emailfrom;
  var subject = document.getElementById(loc + 'txtSubject').value;
     email.subject = subject;
  var oEditor = FCKeditorAPI.GetInstance(loc + 'txtMessage');
  var message = oEditor.GetXHTML();
     email.Message = message;
  var priority = document.getElementById(loc + 'ddlImportance').value;
     email.priority = priority;
  var read = document.getElementById(loc + 'chkReadReceipt').checked;
     email.read = read;
  var own = document.getElementById(loc + 'chkOwn').checked;
     email.own = own;
     //Call to our web service function SendEmailObj
     emailingService.SendEmailObj(loc, email, OnSendEmailComplete, OnError, OnTimeout);
  return false;
 }

 function OnSendEmailComplete(result) {
     
  var pgErr = document.getElementById(result.loc + 'pgError');
  if (result.error) {
  var pgErrHolder = document.getElementById(result.loc + 'pgErrorHolder');
         pgErr.style.display = '';
  if (result.message.indexOf('<br />') != -1) {
             pgErrHolder.style.lineHeight = '15px';
         } else {
             pgErrHolder.style.lineHeight = '30px';
         }
         pgErrHolder.innerHTML = result.message;
     } else {
         pgErr.style.display = 'none';
  var pgNoErr = document.getElementById(result.loc + 'pgNoError');
  var pgNoErrHolder = document.getElementById(result.loc + 'pgNoErrorHolder');
         pgNoErr.style.display = '';
         pgNoErrHolder.innerHTML = result.message;
         document.getElementById(result.loc + 'txtEmailFrom').value = '';
         document.getElementById(result.loc + 'txtSubject').value = '';
  var oEditor = FCKeditorAPI.GetInstance(result.loc + 'txtMessage');
         oEditor.SetHTML('');
         document.getElementById(result.loc + 'ddlImportance').selectedIndex = 0;
         document.getElementById(result.loc + 'chkReadReceipt').checked = false;
         document.getElementById(result.loc + 'chkOwn').checked = false;
     }
 }

 function OnError(result) {
     alert('An error occurred: ' + result);
  return false;
 }

 function OnTimeout(result) {
     alert('You were timed out');
  return false;
 }
 

Our SendEmail JS function creates an instance of our web service iEmail object (var email = new iEmail(); ) and then we retrieve the values from our form elements to populate this object.
The call to the web service function is referenced using the class . function name
You must include the name of the JS function to handle the response from the web service after the parameters. In our case the JS function to handle the response is called OnSendEmailComplete. I have also included functions to handle OnError and OnTimeout.

The OnSendEmailComplete function receives a parameter from the webservice that contains our response object (the return type of our web service function). To access the properties of the object we just use parameterName.PropertyName. In our case I’ve called the parameter result. So our 3 properties are error (boolean), loc(string) and message(string).
We firstly check if an error occurred; if(result.error) and then display the relevant message. Our loc property just makes it easier to access the form elements again. I then just tidy up the form for the next call to the web service

Calling the service from a different domain
You can also call this service from an external domain, either via an aspx or PHP page.

To use the service in another ASP.NET site, you first need to add a reference to the serviceon your new site, in Visual Studio / Web Developer. Go to Solution Explorer, right click on the top level node and select Add Web Reference. In the URL box type the path to your web service http://www.yourdomain.com/services/yourservice.asmx and click Go. The web services it finds will be listed. Add a Web reference name. It normally defaults to com.yourdomain.www. I just changed mine to mynamespace.asmx.emailing
You use this in your .aspx page by having a using / imports statement to your web reference. So, an example page might look something like:-
Code:
 using System;
 using System.Web;
 using System.Web.UI;
 using w3d.asmx.emailing;


 partial class test : System.Web.UI.Page
 {
  public void btnClick(object s, EventArgs e)
     {
  emailingService soapemail = new emailingService();
  iEmail iEmail = New iEmail();
         iEmail.emailTo = "youremail@domain.com";
         iEmail.emailFrom = "anotheremail@anotherdomain.com";
         iEmail.subject = "Your Subject";
         iEmail.message = "Your  Message";

  response response = New response();
         response = soapemail.SendEmailObj("", iEmail);

  if(response.error)
   {
             Label1.Text = "An error occurred<br />" & response.message;
         } else {
             Label1.Text = response.message;
  }


  }

 }
 


The PHP page can be constructed something like this, using PHP5 and the PHP_SOAP extension.[1]
PHP Code:
   <html>
   <head>
   </head>
   <body>
   <?php

      $client 
= new SoapClient('http://www.mydomain.com/services/soapEmail.svc?wsdl');
   
$obj = new StdClass();
   
$obj->oEmail = new StdClass();
   
$obj->oEmail->emailTo "youremail@domain.com";
   
$obj->oEmail->emailFrom "anotheremail@anotherdomain.com";
   
$obj->oEmail->emailCc "";
   
$obj->oEmail->emailBcc "";
   
$obj->oEmail->subject "Your Subject";
   
$obj->oEmail->message "Your Message";
   
$obj->oEmail->priority "Normal";
   
$obj->oEmail->read false;
   
$obj->oEmail->own false;
   
$obj->oEmail->filepath "";
   
$retval $client->SendEmailObj($obj);

      print 
"<p>Returned Message: " $retval->SendEmailObjResult->message "</p>";
   
?>
   </body>
   </html>
I’m not a PHP expert so this is a very simple example. You could include references to form elements etc. to populate the object

Due to the security restrictions on Javascript, it is much more difficult to do cross domain calls using pure Javascript. There are several hacks available to achieve it, including the dynamic script tag and flash hack. You can google these for further information. I may post a separate blog about this once I have played around with it a bit more. The easiest way to achieve this is to make a proxy web service on your client site (a .asmx file, for example) that can be called by Javascript and then the proxy service makes the call to the remote web service.

In the next example I’ll show how to start changing your .asmx file into a WCF .svc file

References

1) http://leifmadsen.wordpress.com/2009/08/04/consuming-soap-complextype-webservice-with-php/

Submit "Convert .asmx file to WCF .svc file to create simple API web service" to Digg Submit "Convert .asmx file to WCF .svc file to create simple API web service" to del.icio.us Submit "Convert .asmx file to WCF .svc file to create simple API web service" to StumbleUpon Submit "Convert .asmx file to WCF .svc file to create simple API web service" to Google

Comments


SEO by vBSEO