An error occurred in script '/home/yhr1ef23xez5/public_html/web2/app/model/bannerhit.php' on line 17:
Undefined index: HTTP_REFERER

Array
(
    [type] => solution
    [name] => sync-web-server
)

WinWrap® | Web Server
logo WinWrap®

Web Server

WinWrap® Basic is an embedded language control available for .NET/COM 32/64 bit Windows applications. The WinWrap® Basic Component is compatible with VBA, Sax Basic, VB.NET and Visual Basic 6.0 style scripts.

Edit, debug and execute scripts in a web server from a BasicIdeCtl control.

Web Server

  • UI process requires a WWAC02X Application Certificate.
  • Collaboratively edit, debug and execute from a BasicIdeCtl control.
  • Scripts managed in a web server (requires a WWAC12 Application Certificate).
  • Collaborative editing requires the Collaborative Editing option on the WWAC12 Application Certificate.

Web Server

Web Server

WinWrap® Basic scripting functionality on a server can be configured to limit user capabilities:

  • No limitations: Requires application level user authentication. (WinWrap® Basic does not provide this.)
  • Safe scripting: See the Secure Scripting best practices solution.
  • Script source: See the Virtual File System best practices solution.
  • Edit only: See the EditOnly property.

WinWrap® Basic inter-process communication requires that the synchronize messages be passed between to the two processes. This example shows how to implement a server using a WCF service containing a BasicNoUIObj object and a client using a BasicIdeCtl control.

Server: WinWrap® Basic in a Web Server

This sample shows how to edit, debug and execute scripts in an embedded Kestrel web server. Two urls are used for communicating WinWrap® Basic synchronize messages with the web server:

namespace winwrap_edit_server.Controllers { [Route("[controller]")] // winwrap public class WinWrapController : Controller { [HttpPost("requests")] public IActionResult Requests([FromBody]WinWrapMessage postdata) { string request = postdata.ToString(); WinWrapBasicService.Singleton.SendRequests(request); return Ok(new WinWrapMessage("[]")); } [HttpPost("responses/{ids}")] public IActionResult Responses(string ids, [FromBody]WinWrapMessage postdata) { SortedSet<int> idset = new SortedSet<int>(); foreach (string idx in ids.Split('-')) if (int.TryParse(idx, out int id)) idset.Add(id); string responses = WinWrapBasicService.Singleton.GetResponses(idset); return Ok(new WinWrapMessage(responses)); } } }

The requests url sends the request messages to the BasicNoUIObj object and the responses url gets the queued synchronizing messages from the BasicNoUIObj object.

namespace winwrap_edit_server { public class WinWrapBasicService { BasicThread basic_thread_ = new BasicThread(); WinWrap.Basic.IVirtualFileSystem filesystem_; string log_file_; static object lock_ = new object(); static WinWrapBasicService singleton_; WWB.SynchronizingQueues responses_sqs_ = new WWB.SynchronizingQueues(); public static WinWrapBasicService Singleton { get { lock (lock_) { if (singleton_ == null) singleton_ = new WinWrapBasicService(); return singleton_; } } } private WinWrapBasicService() { } public static void Shutdown() { if (singleton_ != null) { singleton_.basic_thread_.Kill(); singleton_ = null; } } public void Initialize(IDictionary<string, object< parameters, CancellationToken cancellationToken) { log_file_ = (string)parameters[".log_file"]; if (log_file_ != null) File.WriteAllText(log_file_, ""); string scriptroot = (string)parameters["scriptroot"]; filesystem_ = new WWB.MyFileSystem(scriptroot); string root = filesystem_.Combine(null, null); bool reset = (bool)parameters["reset"]; if (!Directory.Exists(root)) { reset = true; Directory.CreateDirectory(root); } if (reset) { // copy samples to the virtual file system foreach (string res_name in WWB.Util.GetResourceFileNames("Samples")) { string sample = WWB.Util.ReadResourceTextFile("Samples." + res_name, false); string file_name = root + "\\" + res_name; File.WriteAllText(file_name, sample); } } bool debug = (bool)parameters["debug"]; bool sandboxed = (bool)parameters["sandboxed"]; SynchronizationContext sc = new SynchronizationContext(); basic_thread_.SendAction(basic => { // configure basic basic.Synchronizing += (sender, e) => { // response/notification from the remote BasicNoUIObj sc.Post(state => { Log(e.Param); lock (lock_) responses_sqs_.Enqueue(e.Param, e.Id); }, null); }; basic.ReceivedAppSyncMessage += (sender, e) => { basic.SendAppSyncMessage(e.Data, -1); }; Util.IgnoreDialogs = true; basic.Secret = new Guid(Secret.MySecret); basic.Initialize(); basic.EditOnly = !debug; basic.Sandboxed = sandboxed; basic.BlockedKeywords = "AboutWinWrapBasic Beep Dialog GetFilePath InputBox MsgBox ShowPopupMenu"; basic.VirtualFileSystem = filesystem_; basic.SynchronizedEdit = true; // synchronized editing }); } public string LogFile { get { return log_file_; } set { log_file_ = value; if (log_file_ != null) File.WriteAllText(log_file_, ""); } } public string GetResponses(SortedSet<int> idset) { // keep ids alive basic_thread_?.PostAction(basic => { foreach (int id in idset) basic.Synchronize("[]", id); }); WWB.SynchronizingQueue sq = new WWB.SynchronizingQueue(0); lock (lock_) foreach (int id in idset) sq.Enqueue(responses_sqs_.Dequeue(id)); return sq.DequeueAll(); } public void SendRequests(string requests) { Log(requests); basic_thread_?.PostAction(basic => basic.Synchronize(requests, 0)); } private void Log(string text) { if (log_file_ != null && text != "[]") { if (text.StartsWith("[") && text.EndsWith("]")) text = text.Substring(1, text.Length - 2); text = text.Replace("\r\n{", "_{"); text = text.Replace("\r\n", "") + "\r\n"; text = text.Replace("_{", "\r\n{"); text = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss\r\n") + text; lock (lock_) File.AppendAllText(log_file_, text + "\r\n"); if (text.IndexOf("\"response\":\"!attach\"") >= 0 || text.IndexOf("\"response\":\"!detached\"") >= 0) Console.WriteLine(text); } } } }

Sample code for the web server is available.

Client: WinWrap® Basic in a Windows Application

The user can edit, debug and scripts using a client process which contains a WinWrap® Basic IDE communicating with the web server. The client process uses the web server urls to communicate with the remote BasicNoUIObj object:

namespace SyncWebClient { class Transport { HttpClient http_client_; string base_request_uri_ = "http://localhost:5000/winwrap/requests/"; string base_response_uri_ = "http://localhost:5000/winwrap/responses/"; int sync_id_; public Transport() { // create and initialize the HTTP client http_client_ = new HttpClient(); http_client_.DefaultRequestHeaders.Accept.Clear(); http_client_.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/winwrap")); } public void SetSyncId(int sync_id) { sync_id_ = sync_id; } async public Task PollingLoop(BasicIdeCtl basic) { // get responses task while (http_client_ != null) { string responses = null; try { // get responses responses = await GetResponses(sync_id_.ToString()); } catch (Exception ex) { Debug.Print(ex.ToString()); } if (responses != null) { // send the response to the IDE basic.Synchronize(responses, 0); } } } async public Task<string> GetResponses(string ids) { // get responses string uri = base_response_uri_ + ids; StringContent content = new StringContent("", Encoding.UTF8, "application/winwrap"); HttpResponseMessage response = await http_client_.PostAsync(uri, content); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } async public Task SendRequests(string requests) { // send requests string uri = base_request_uri_; StringContent content = new StringContent(requests, Encoding.UTF8, "application/winwrap"); HttpResponseMessage response = await http_client_.PostAsync(uri, content); response.EnsureSuccessStatusCode(); } public void Dispose() { if (http_client_ != null) { HttpClient http_client = http_client_; http_client_ = null; http_client.CancelPendingRequests(); http_client.Dispose(); } } } }
namespace SyncWebClient { public partial class Form1 : Form { Transport transport_ = new Transport(); bool polling_loop_active_; public Form1() { InitializeComponent(); } private void Shutdown() { if (transport_ != null) { // dispose the transport transport_.Dispose(); transport_ = null; // wait for polling loop to end while (!polling_loop_active_) { WinWrap.Basic.Util.DoEvents(); Thread.Sleep(50); } } } private void Form1_Load(object sender, EventArgs e) { // start the polling task transport_.PollingLoop(basicIdeCtl1).ContinueWith(task => polling_loop_active_ = true); // attach basicIdeCtl1.SynchronizedEdit = true; if (!basicIdeCtl1.Synchronized) { // attach failed Close(); return; } // set the transports synchronized id transport_.SetSyncId(basicIdeCtl1.SynchronizedId); // open Sample1.bas basicIdeCtl1.FileName = "\\Sample1.bas"; } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { Shutdown(); } private void basicIdeCtl1_Disconnected(object sender, EventArgs e) { Shutdown(); } async private void basicIdeCtl1_Synchronizing(object sender, WinWrap.Basic.Classic.SynchronizingEventArgs e) { if (e.Param == "[]") return; // disable Synchronizing event basicIdeCtl1.SynchronizingInterval = -1; try { // send the request and get the response (non-blocking "wait" for task to complete) await transport_.SendRequests(e.Param); } catch (AggregateException aggregateException) { int n = 0; string messages = null; foreach (Exception ex in aggregateException.InnerExceptions) messages += $"{++n}) {ex.Message}\r\n"; Debug.Print(messages); } catch (Exception ex) { Debug.Print(ex.Message); } finally { // reactivate the Synchronizing event (50 milliseconds) basicIdeCtl1.SynchronizingInterval = 50; } } } }

Sample code for the Windows Application web client is available.

  • Run the web server from Visual Studio.
    Server
  • Run a http client from Visual Studio.
    Client
  • All editing, debugging and execution controlled from the client occurs in the web server.
  • Multiple clients can collaboratively edit the same script.

Client/Server Solutions:

Cross Thread

Inter-Process

Web Server

Web Page Client

Copyright Polar Engineering, Inc.