Question

I've written a small hello world test app in Silverlight which i want to host on a Linux/Apache2 server. I want the data to come from MySQL (or some other linux compatible db) so that I can databind to things in the db.

I've managed to get it working by using the MySQL Connector/.NET:

MySqlConnection conn = new MySqlConnection("Server=the.server.com;Database=theDb;User=myUser;Password=myPassword;");
conn.Open();
MySqlCommand command = new MySqlCommand("SELECT * FROM test;", conn);
using (MySqlDataReader reader = command.ExecuteReader())
{
     StringBuilder sb = new StringBuilder();
     while (reader.Read())
     {
         sb.AppendLine(reader.GetString("myColumn"));
     }
     this.txtResults.Text = sb.ToString();
}

This works fine if I give the published ClickOnce app full trust (or at least SocketPermission) and run it locally.

I want this to run on the server and I can't get it to work, always ending up with permission exception (SocketPermission is not allowed).

The database is hosted on the same server as the silverlight app if that makes any difference.

EDIT Ok, I now understand why it's a bad idea to have db credentials in the client app (obviously). How do people do this then? How do you secure the proxy web service so that it relays data to and from the client/db in a secure way? Are there any examples out there on the web?

Surely, I cannot be the first person who'd like to use a database to power a silverlight application?

Was it helpful?

Solution

The easiest way to do what you want (having read through your edits now :)) will be to expose services that can be consumed. The pattern that Microsoft is REALLY pushing right now is to expose WCF services, but the truth is that your Silverlight client can use WCF to consume a lot of different types of services.

What may be easiest for you to do right now would be to use a .NET service on a web server or maybe a PHP REST service, and then point your Silverlight app at that service. By doing so, you're protecting your database not only from people snooping through it, but more importantly, you're restricting what people can do to your database. If your data is supposed to be read-only, and your service's contract only allows reading operations, you're set. Alternatively, your service may negotiate sessions with credentials, again, set up through WCF.

WCF can be a client-only, server-only, or client-server connector platform. What you choose will affect the code you write, but it's all going to be independent of your database. Your code can be structured such that it's a one-to-one mapping to your database table, or it can be far more abstract (you can set up classes that represent full logical views if you choose).

OTHER TIPS

While the "official" answer is to use WCF to push a service to Silverlight, I kind of figure that anyone using MySQL would probably not be using a complete ASP.NET solution. My solution was to build a PHP webservice (like Rob suggested) to interact with the MySQL database and have the Silverlight access it in a RESTful manner.

Here is beginning of a three part tutorial for using Silverlight to access a MySQL database through a PHP web service:

PHP, MySQL and Silverlight: The Complete Tutorial

Silverlight does not have any capability to directly access database servers. What you can do is to expose your database operations through web services (ASMX or WCF, even non-.NET!) and use Silverlight to access those services.

I just got this working; ASP.NET4 site with Silverlight4 content on Linux Ubuntu 10 / Apache2 server. Content is developed using Visual Studio 2010. VS2008 should work fine too.

Server:

  • Setup a Linux server with Apache2 and MySQL, there are tons of guides on this.
    • Make sure MySQL is accessible from the development PC and optionally from the Internet. See here for details: Causes of Access-Denied Errors.
    • Setup the database table structures and add some content for testing later. In our example we assume you have the table 'persons' with the column 'name'.
  • Since Silverlight is a client-side technology you are pretty much good-to-go and can host the application with a simple HTML page.
  • A web service is required between Silverlight and MySQL. Microsoft's WCF RIA is one flavor, but requires .NET. On the plus-side, you get to host ASP.NET4 pages as well. Here is a thorough guide to setting it up: Setting up Mono 2.8 with Asp.Net 4.0 and MVC2 on Ubuntu with MySql Membership

Visual Studio:

  • Install latest MySQL Connector/Net and restart VS
  • Add your MySQL database as data source
    • Open Server Explorer -> Add data connection -> Select 'MySQL Database'
    • Fill in credentials and test connection

Setting up the site with MySQL access:

Here is a guide I found helpful: Step By Step Guide to WCF RIA enabled SL4 application with Entity Framework

  • Create or open a Silverlight project.
    • The server-side project is typically named 'ProjectName.Web'
    • The client-side project is typically named 'ProjectName'
  • Add 'ADO.NET Entity Data Model' to the server project. This will be a model of your database structure.
    • Select 'Generate from database'
    • Choose the MySQL database connection you created
    • Select the tables you want to access
  • Build your solution now before proceeding.
  • Add 'Domain Service Class' to the server project, f.ex. 'FooDomain'. This will make the database entities available to the client-side Silverlight code.
    • In 'Available DataContext/ObjectContext classes:' select the Entity Framework model you created in the previous step.
    • Check the entities you want to access and check 'Enable editing' where appropriate
    • Check 'Generate associated classes for metadata'
  • Build your solution again to generate 'FooDomainContext', based on 'FooDomain' in server project.

Testing:

Let's get data from MySQL into Silverlight. Assuming there is a table named 'persons' with column name 'name', we can bind a list box to show the names of the persons.

First add a Silverlight page, let's say 'Home'. In Home.xaml add:

<ListBox x:Name="TestList" Width="100" />

In Home.xaml.cs file add:

public partial class Home : Page
{
    public Home()
    {
        InitializeComponent();

        Loaded += Home_Loaded;
    }

    void Home_Loaded(object sender, RoutedEventArgs e)
    {
        var context = new FooDomainContext();
        var query = context.Load(context.GetPersonsQuery());
        TestList.ItemsSource = query.Entities;
        TestList.DisplayMemberPath = "name";
    }
}

Here we assume you named your domain service 'FooDomain', and this would generate the 'FooDomainContext' class used.

Hopefully, if all is set up properly, you will now see a list of person names when running your Silverlight project.

Edit: ASP.NET is not optional, but required for the WCF RIA web service used in my example.

Having DB connections directly to the server from the client side is usually a bad idea. I don't know how easy it is to decompile a Silverlight app, but I would guess it's possible in some way. Then you're basically giving away your DB credentials to your users.

You can get data from MySQL by using Web Services.

Walkthrough:

Step 1: Create Web Services

Step 2: Add Service Reference to Silverlight


Step 1: Create Web Services

Add a new Silverlight project.

Add a new Silverlight project

Create a new Web Service. Right click on the web project > Add > New Item

Create a new Web Service

Select "Web Service".

enter image description here

Initial code of a new Web Service.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;

namespace SilverlightApplication1.Web
{
    /// <summary>
    /// Summary description for WebService1
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class WebService1 : System.Web.Services.WebService
    {
        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World";
        }
    }
}

In order for the Web Service able to connect to MySQL, we need to add a reference of MySql.Data.DLL into the web project and add the Using statement at top of the Web Service class:

using MySql.Data.MySqlClient; 

HelloWorld() is an initial sample method created by Visual Studio. You may want to delete it as it is not needed. I'm going to create 2 simple method to demonstrate how Web Services are used to communicate between SilverLight and MySQL.

First method: ExecuteScalar()

This method is simple. Get a single object from MySQL.

public string ExecuteScalar(string sql)
{
    try
    {
        string result = "";
        using (MySqlConnection conn = new MySqlConnection(constr))
        {
            using (MySqlCommand cmd = new MySqlCommand())
            {
                conn.Open();
                cmd.Connection = conn;
                cmd.CommandText = sql;
                result = cmd.ExecuteScalar() + "";
                conn.Close();
            }
        }
        return result;
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
} 

Second method: ExecuteNonQuery()

For single SQL execution. Example of SQL type: INSERT, UPDATE, DELETE.

public string ExecuteNonQuery(string sql)
{
    try
    {
        long i = 0;
        using (MySqlConnection conn = new MySqlConnection(constr))
        {
            using (MySqlCommand cmd = new MySqlCommand())
            {
                conn.Open();
                cmd.Connection = conn;
                cmd.CommandText = sql;
                i = cmd.ExecuteNonQuery();
                conn.Close();
            }
        }
        return i + " row(s) affected by the last command, no resultset returned.";
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
}  

This is how the Web Service looks like after adding the two methods above:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using MySql.Data.MySqlClient;

namespace SilverlightApplication1.Web
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class WebService1 : System.Web.Services.WebService
    {
        string constr = "server=localhost;user=root;pwd=1234;database=test;";

        [WebMethod]
        public string ExecuteScalar(string sql)
        {
            try
            {
                string result = "";
                using (MySqlConnection conn = new MySqlConnection(constr))
                {
                    using (MySqlCommand cmd = new MySqlCommand())
                    {
                        conn.Open();
                        cmd.Connection = conn;
                        cmd.CommandText = sql;
                        result = cmd.ExecuteScalar() + "";
                        conn.Close();
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        [WebMethod]
        public string ExecuteNonQuery(string sql)
        {
            try
            {
                long i = 0;
                using (MySqlConnection conn = new MySqlConnection(constr))
                {
                    using (MySqlCommand cmd = new MySqlCommand())
                    {
                        conn.Open();
                        cmd.Connection = conn;
                        cmd.CommandText = sql;
                        i = cmd.ExecuteNonQuery();
                        conn.Close();
                    }
                }
                return i + " row(s) affected by the last command, no resultset returned.";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }  
    }
} 

You will notice that an attribute of [WebMethod] is added to the methods.

Rebuild the project and let the Web Service be ready for next step.

Rebuild the project

Web Service Access Permission

Please note that, by default, Web Service only allow those Silverlight that is hosted at the same domain with the Web Service to access. If the Silverlight application is hosted on another website/domain, Web Service will deny the communication. Therefore we have to configure the permission for the Web Service to be accessed by Silverlight which is hosted at different domain.

You have to create two additional files: clientaccesspolicy.xml and crossdomain.xml.

These files has to be put at the root of the domain where the Web Services are hosted.

Example: http://www.mywebsite.com/clientaccesspolicy.xml and http://www.mywebsite.com/crossdomain.xml

clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

If you only want to allow the Web Service to be accessed by specific domain (example: www.myanotherwebsite.com), you can add it within . Example:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="http://www.myanotherwebsite.com"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

crossdomain.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM 
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
</cross-domain-policy>

To understand more about this, please read: Making a Service Available Across Domain Boundaries (MSDN)


Step 2: Add Service Reference to Silverlight

Add a Service Reference to Silverlight.

Add a Service Reference to Silverlight

Type the address of the Web Service and press [Go].

Example of address: http://www.mywebsite.com/MyCoolWebService.asmx

Change the Namespace to your favor, and press [OK].

Web Service Browser

Visual Studio will analyze the Web Service, do the data binding and create a class.

Before continue coding, let's us see what methods that we can use in the new created class. Right click the new class and select [View in Object Browser].

View in Object Browser

The class that we are going to use is WebService1SoapClient (in this example). The naming is based on the Service name. If we name our service class as MyCoolWebService, then MyCoolWebServiceSoapClient will be chosen as the name of the class in Silverlight. At the right panel, two methods and two events are highlighted. Those are the methods used to call the Web Services.

Object of WebService1SoapClient

Lets create a simple Silverlight application by adding a Textbox and two Buttons.

In this example, user will key in SQL query directly into the Textbox.

Button of [ExecuteScalar] will send the SQL to the Web Service and retrieve data back. (SELECT, SHOW, etc.)

Button of [ExecuteNonQuery] will send the SQL to the Web Service for execution only. (INSERT, UPDATE, DELETE, etc.)

Design a simple SilverLight App

This is the initial code behind of MainPage.xaml:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void btExecuteScalar_Click(object sender, RoutedEventArgs e)
        {
        }

        private void btExecuteNonQuery_Click(object sender, RoutedEventArgs e)
        {
        }
    }
}

Now, these are what we are going to do here:

  • Declare the service as static object at class level: ServiceReference1.WebService1SoapClient
  • Create the service completed event of the two methods.
  • Call the service in the event of button click.
  • Display the service result: MessageBox.Show()


public partial class MainPage : UserControl
{
    ServiceReference1.WebService1SoapClient myService;

    public MainPage()
    {
        InitializeComponent();
        myService = new ServiceReference1.WebService1SoapClient();
        myService.ExecuteScalarCompleted += myService_ExecuteScalarCompleted;
        myService.ExecuteNonQueryCompleted += myService_ExecuteNonQueryCompleted;
    }

    void myService_ExecuteNonQueryCompleted(object sender, 
                   ServiceReference1.ExecuteNonQueryCompletedEventArgs e)
    {
        MessageBox.Show(e.Result);
    }

    void myService_ExecuteScalarCompleted(object sender, 
         ServiceReference1.ExecuteScalarCompletedEventArgs e)
    {
        MessageBox.Show(e.Result);
    }

    private void btExecuteScalar_Click(object sender, RoutedEventArgs e)
    {
        myService.ExecuteScalarAsync(textBox1.Text);
    }

    private void btExecuteNonQuery_Click(object sender, RoutedEventArgs e)
    {
        myService.ExecuteNonQueryAsync(textBox1.Text);
    }
}

Press [F5], run and test the Silverlight application.

Testing

Testing

Testing

Together with your creativity, I believe you can do something more than this for now Smile | :)

If you have done any changes to the Web Service, maybe you added new Service (new web methods), you have to update the Service Reference at Silverlight to re-bind the Services. You might want to update the Web Service address, if you uploaded the files to a different web hosting.

update the Service Reference

Happy coding.

Read More:

  1. Original Post - Connecting MySQL From SilverLight With Web Services - CodeProject.com (written by me)
  2. Access a Web Service from a Silverlight Application
  3. HOW TO: Write a Simple Web Service by Using Visual C# .NET
  4. How to: Build a Service for Silverlight Clients
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top