Introduction
In this tip, I will explain how to display your application things in your WebPanel
.
The project contains:
WebPanel
DLL - Contains class for starting your own web panel
- Test Application - Simple application to test if WebPanel works
- Htdocs folder - Contains a CMS to create your panel
- MySQL dump - You need to import this dump file to your MySQL server to use CMS
Screenshot and Video
Test Application
Simple application to test if all works. WebService
requires to start the application as administrator.
Form Code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
WebPanel MyWebPanel;
public static int runningtime_seconds = 0;
public static int MyCounter = 0;
public static string MyText;
public static List<User> Users;
private void Form1_Load(object sender, EventArgs e)
{
Users = new List<User>();
Users.Add(new User("Jon", 30, "United States"));
Users.Add(new User("Mario", 20, "Italy"));
foreach (User user in Form1.Users)
{
listBox1.Items.Add(user.Name);
}
MyWebPanel = new WebPanel(IPAddress.Parse("127.0.0.1"),
8000, "admin", "password");
LoginValidator.OnLoginAttempt +=
new LoginValidator.onLoginAttemptHandler(onLoginAttempt);
WebPanel.AfterReceiveRequest +=
new WebPanel.AfterReceiveRequestHandler(AfterReceiveRequest);
WebPanel.OnException += new WebPanel.OnExceptionHandler(OnException);
MyWebPanel.Start(typeof(WebPanelHandler), typeof(IWebPanel));
}
void onLoginAttempt(object sender, bool response)
{
richTextBox1.BeginInvoke(new MethodInvoker(delegate() {
richTextBox1.AppendText("Login response: " + response + Environment.NewLine); }));
}
void AfterReceiveRequest(object sender, ref System.ServiceModel.Channels.Message request,
IClientChannel channel, InstanceContext instanceContext)
{
var action = OperationContext.Current.IncomingMessageHeaders.Action;
var operationName = action.Substring(action.LastIndexOf("/") + 1);
richTextBox1.BeginInvoke(new MethodInvoker(delegate() {
richTextBox1.AppendText(operationName + " invoked" + Environment.NewLine); }));
}
void OnException(object sender, Exception e)
{
MessageBox.Show(e.Message);
}
private void button1_Click(object sender, EventArgs e)
{
MyCounter++;
label2.Text = "Value: " + MyCounter;
}
private void timer1_Tick(object sender, EventArgs e)
{
runningtime_seconds++;
label1.Text = "Running time: " + runningtime_seconds+" seconds";
richTextBox1.ScrollToCaret();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MyText = textBox1.Text;
}
}
WebPanel Methods
Methods that will be invoked from the CMS.
public class WebPanelHandler : IWebPanel
{
public int RunningTime()
{
return Form1.runningtime_seconds;
}
public int MyCounter()
{
return Form1.MyCounter;
}
public string MyText()
{
return Form1.MyText;
}
public void CloseApplication()
{
if (MessageBox.Show("Do you really want to close application?",
"Confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
Application.Exit();
}
}
public string GetUserInfo(string username, string age)
{
if (username == "" && age == "")
return null;
foreach (User user in Form1.Users)
{
int uage = 0;
int.TryParse(age, out uage);
if (user.Name.ToLower() == username.ToLower() || user.Age == uage)
{
return "Name: " + user.Name + "<br>Age: " +
user.Age + "<br>Country: " + user.Country;
}
}
return null;
}
}
WebPanel interface
Contains method signatures.
[ServiceContract]
public interface IWebPanel
{
[OperationContract]
int RunningTime();
[OperationContract]
int MyCounter();
[OperationContract]
void CloseApplication();
[OperationContract]
string MyText();
[OperationContract]
string GetUserInfo(string username, string age);
}
DLL
Contains class to start the WebPanel
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Reflection;
namespace Web.Panel
{
public class LoginValidator : UserNamePasswordValidator
{
public delegate void onLoginAttemptHandler(object sender, bool response);
public static event onLoginAttemptHandler OnLoginAttempt;
[System.Diagnostics.DebuggerHidden]
public override void Validate(string userName, string password)
{
if ((userName != WebPanel.Username) || (password != WebPanel.Password))
{
if (OnLoginAttempt != null)
OnLoginAttempt(this, false);
throw new SecurityTokenException();
}
else
{
if (OnLoginAttempt != null)
OnLoginAttempt(this, true);
}
}
}
public class WebPanel
{
private IPAddress IP;
private int Port;
public static string Username;
public static string Password;
public delegate void AfterReceiveRequestHandler(object sender,
ref Message request, IClientChannel channel, InstanceContext instanceContext);
public static event AfterReceiveRequestHandler AfterReceiveRequest;
public delegate void BeforeSendReplyHandler(object sender,
ref Message reply, object correlationState);
public static event BeforeSendReplyHandler BeforeSendReply;
public delegate void OnExceptionHandler(object sender, Exception e);
public static event OnExceptionHandler OnException;
public WebPanel(IPAddress IP, int Port, string username, string password)
{
this.IP = IP;
this.Port = Port;
Username = username;
Password = password;
}
class webServiceEvent : IEndpointBehavior, IDispatchMessageInspector
{
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior
(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
}
public void Validate(ServiceEndpoint endpoint)
{
}
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
{
if (WebPanel.AfterReceiveRequest != null)
WebPanel.AfterReceiveRequest
(this, ref request, channel, instanceContext);
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
if (WebPanel.BeforeSendReply != null)
WebPanel.BeforeSendReply(this, ref reply, correlationState);
}
}
public bool Start(Type serviceType, Type implementedContract)
{
if (OnException == null)
{
throw new Exception("Assign a exception handler");
}
Uri baseAddress = new Uri("http://" + IP.ToString() +
":" + Port + "/WebPanel/");
ServiceHost selfHost = new ServiceHost(serviceType, baseAddress);
BasicHttpBinding http = new BasicHttpBinding();
http.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
http.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
try
{
ServiceEndpoint endpoint = selfHost.AddServiceEndpoint(
implementedContract, http, "RemoteControlService");
endpoint.Behaviors.Add(new webServiceEvent());
selfHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode =
UserNamePasswordValidationMode.Custom;
selfHost.Credentials.UserNameAuthentication.
CustomUserNamePasswordValidator = new LoginValidator();
ServiceMetadataBehavior smb =
selfHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
}
try
{
selfHost.Open();
return true;
}
catch (Exception e)
{
if (e is AddressAccessDeniedException)
{
if (OnException != null)
OnException(this, e);
return false;
}
if (e is AddressAlreadyInUseException)
{
if (OnException != null)
OnException(this, e);
return false;
}
}
}
catch (CommunicationException ce)
{
if (OnException != null)
OnException(this, ce);
selfHost.Abort();
return false;
}
return false;
}
}
}
CMS
Element Class
Generate the HTML code for the element.
<?php
class Element {
private $id;
private $title;
private $methodname;
private $type;
private $refreshrate;
private $parameters;
public function Element
($id, $title, $methodname, $type, $refreshrate, $parameters) {
$this->id = $id;
$this->title = $title;
$this->methodname = $methodname;
$this->type = $type;
$this->refreshrate = $refreshrate;
$this->parameters = $parameters;
}
public function getHtml() {
echo '<div class="box" style="margin:8px;
display:inline-block;"><div name="title">
<h3 style="margin: 0; float:left;">'.
$this->title .'</h3>';
echo '<a href="deleteelement.php?id='.
$this->id.'"><img style="margin-left: 2px;
float: right;" src="./images/delete.png">
</img></a></div><br><br>';
if($this->type == 0)
{
echo '<div id="' .
$this->methodname . 'result">';
echo objectToArray(Invoke($this->methodname))
[$this->methodname . "result"];
echo '</div>';
}
if ($this->type == 1)
{
echo '<a href="?invoke=' .
$this->methodname . '"><button
type="button">Invoke</button></a>';
}
if ($this->refreshrate > 0)
{
echo '<script type="text/javascript">';
echo 'function ' . $this->methodname . '_read()
{
var ' . $this->methodname .'xmlhttp = AJAX();
' . $this->methodname .'xmlhttp.onreadystatechange=function(){
if(' . $this->methodname .'xmlhttp.readyState==4){
var obj = jQuery.parseJSON(' .
$this->methodname .'xmlhttp.responseText);
document.getElementById("' .
$this->methodname . 'result").innerHTML= obj
["' . strtolower($this->methodname) .'result"];
setTimeout("' . $this->methodname .
'_read()",' . $this->refreshrate * 1000 . ');
}
}
' . $this->methodname .'xmlhttp.open
("GET","panel.php?getmethod=' .
$this->methodname .'",true);
' . $this->methodname .'xmlhttp.send(null);
}';
echo 'addLoadEvent(' . $this->methodname . '_read())';
echo '</script>';
}
if ($this->type == 2 && $this->parameters != "")
{
$parameter = explode(',', $this->parameters);
foreach($parameter as $key) {
if ($key != "")
{
echo $key . "<br>";
echo '<input type="text" name="' .
$key . '" id="' . $key . '">';
}
}
echo "<button onClick='InvokeWithParameters
(\"" . $this->methodname . "\",\"" .
$this->parameters . "\")'
type='button'>Invoke</button>";
echo '<div id="' .
$this->methodname . 'result">';
echo '</div>';
}
echo '</div>';
}
}
?>
webServiceConnector
Connects to a webservice
, invokes a method and returns its response.
<?php
$client = new SoapClient("http://localhost:8000/WebPanel/?wsdl",array(
'login' => "admin", 'password' => "password"));
function Invoke($methodname)
{
try
{
global $client;
$response = $client->__soapCall($methodname,array());
return $response;
}
catch (SoapFault $exception)
{
trigger_error("SOAP Fault:
(faultcode: {$exception->faultcode}, faultstring:
{$exception->faultstring})");
}
}
function InvokeWithParameters($methodname, $parameters)
{
try
{
global $client;
$temp = explode (',',$parameters,-1);
foreach ($temp as $pair)
{
list ($k,$v) = explode ('|',$pair);
$pairs[$k] = $v;
}
$array = array("parameters" => $pairs);
$response = $client->__soapCall($methodname, $array);
return $response;
}
catch (SoapFault $exception)
{
trigger_error("SOAP Fault:
(faultcode: {$exception->faultcode}, faultstring:
{$exception->faultstring})");
}
}
function objectToArray($d) {
if (is_object($d)) {
$d = get_object_vars($d);
}
if (is_array($d)) {
return array_change_key_case(array_map(__FUNCTION__, $d), CASE_LOWER);
}
else {
return $d;
}
}
?>
How to Setup CMS
- Change MySQL connection parameters in /htdocs/mysql.php
- Change your
WebPanel ip:port
and username
, password
in /htdocs/includes/webServiceConnector.php
- Open web browser and head to yoursite/register.php and create admin account (delete register.php after)
- Make login
Add a New Element to the WebPanel
Element title
: Element name that will be displayed on WebPanel
Method name
: The method name that you declared in IWebPanel
. The CMS will invoke it and will display its response.
Type
: "Show value" for method with text response, "Action" for a void
method or "With parameters" for methods with parameters
Refresh every
: Refresh element every x seconds (Only on "show value" element type)
Add a Web Panel to your Application
- Add reference to WebPanel.dll
- Add:
using System.ServiceModel;
using Web.Panel;
- Create a
WebPanel
variable
WebPanel MyWebPanel;
- Add the code to start the
WebPanel
in your method:
MyWebPanel = new WebPanel(IPAddress.Parse("127.0.0.1"),
8000, "admin", "changeme");
LoginValidator.OnLoginAttempt += new LoginValidator.onLoginAttemptHandler(onLoginAttempt);
WebPanel.AfterReceiveRequest += new WebPanel.AfterReceiveRequestHandler(AfterReceiveRequest);
WebPanel.OnException += new WebPanel.OnExceptionHandler(OnException);
MyWebPanel.Start(typeof(WebPanelHandler), typeof(IWebPanel));
- Add events handler methods:
void onLoginAttempt(object sender, bool response)
{
}
void AfterReceiveRequest(object sender, ref System.ServiceModel.Channels.Message request,
IClientChannel channel, InstanceContext instanceContext)
{
}
void OnException(object sender, Exception e)
{
}
- Add
WebPanelHandler
class and its interface:
public class WebPanelHandler : IWebPanel
{
}
[ServiceContract]
public interface IWebPanel
{
}
Conclusion
Thanks for reading this tip, I hope you liked it!
Let me know if you have suggestions to improve it, I'll be happy to implement them.
History
- Version 1.0 - 22/07/2013
- 25/07/2013 - Added video and conclusion
- 27/07/2013 - Added support for methods with parameters
- 06/12/2014 - Text formatting