There is no “synchronized” handler. Every request is passed on a thread – so if you have shared resources your code has to be thread safe. You should simply create an ashx page in your Wisej app or in a separate asp.net app (makes no difference). This is the easiest way and doesn’t require any registration in web.config. Return true for the IsReusable property so only 1 instance is created to handle the requests.
You can save the token in an instance field and retrieve it in a synchronized block (lock block). Don’t worry about the threads, that’s handled by asp.net and the thread pool. You can tweak the thread pool settings in the web.config file, but I’d leave it alone.
The async IHttpAsyncHandler you are referring to doesn’t change anything in terms of requests and threads. All it does is to allow the code in the handler to return the thread to the thread pool when/if it has to wait for another thread to finish, like an external process or an async db request. It doesn’t save threads and doesn’t optimize much.
Wisej uses the IHttpAsyncHandler for the HTTP requests because it allows us to return from the request while suspending the thread when entering the server modal state for modal dialogs.
Hi Darren,
You are right. Logged as WJ9101
Hi Kevin,
Did you try it running Wisej 1.5.9?
Hi David,
I don’t quite understand the issue you report. Can you provide some details? Are you trying to run demos on Visual Studio? If so, what is your environment?
Hi Tung Ngo,
Can you attach a sample reproducing the issue?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using Wisej.Web;
namespace MyApp.CustomControls {
public class SearchComboBox : Wisej.Web.ComboBox {
public int minLength { get; set; }
public dynamic obj { get; set; }
public string displayField { get; set; }
public string valueField { get; set; }
public bool limitToList { get; set; }
public TextBox idTextBox { get; set; }
public string defaultId { get; set; }
public bool showInitialList { get; set; }
public SearchComboBoxType searchType { get; set; }
private string[] data { get; set; }
private bool found { get; set; }
public SearchComboBox() {
this.KeyUp += SearchComboBox_KeyUp;
this.TextChanged += SearchComboBox_TextChanged;
this.Leave += SearchComboBox_Leave;
}
public void Set(dynamic ClassList, TextBox TextBoxForIdField, string DisplayItem, string IdItem = "", int MinimumLengthBeforeSearch = 2, bool LimitToList = true, bool ShowInitialList = true, string DefaultIdFieldValue = "0", SearchComboBoxType SearchComboBoxType = SearchComboBoxType.Contains){
obj = ClassList;
idTextBox = TextBoxForIdField;
displayField = DisplayItem;
if (IdItem == "") {
valueField = DisplayItem;
} else {
valueField = IdItem;
}
minLength = MinimumLengthBeforeSearch;
limitToList = LimitToList;
defaultId = DefaultIdFieldValue;
showInitialList = ShowInitialList;
searchType = SearchComboBoxType;
MakeTheMagicHappen();
}
public void MakeTheMagicHappen() {
int cnt = obj.Count;
data = new string[cnt];
for (int i = 0; i < cnt; i++) {
var changedItem = ToExpandoObject(obj[i]);
var dictItem = changedItem as IDictionary<string, object>;
data[i] = dictItem[displayField].ToString();
}
idTextBox.Text = defaultId;
if (showInitialList) {
ComboFill(obj, valueField, displayField);
}
}
private void SearchComboBox_KeyUp(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.Back) {
int sStart = this.SelectionStart;
if (sStart > 0) {
sStart--;
if (sStart == 0) {
this.Text = defaultId;
} else {
this.Text = this.Text.Substring(0, sStart);
}
}
e.Handled = true;
}
}
private void SearchComboBox_TextChanged(object sender, EventArgs e) {
HandleTextChanged();
found = false;
foreach (var o in obj) {
if (o.Name == this.Text) {
idTextBox.Text = o.Id.ToString();
found = true;
break;
}
}
if (!found) {
idTextBox.Text = defaultId;
}
}
private void HandleTextChanged() {
var txt = this.Text;
if (txt.Length > (minLength - 1)) {
IEnumerable<string> list = null;
switch (searchType) {
case SearchComboBoxType.Contains:
list = from d in data
where d.ToUpper().Contains(this.Text.ToUpper())
select d;
break;
case SearchComboBoxType.StartOnly:
list = from d in data
where d.ToUpper().StartsWith(this.Text.ToUpper())
select d;
break;
case SearchComboBoxType.EndOnly:
list = from d in data
where d.ToUpper().EndsWith(this.Text.ToUpper())
select d;
break;
}
if (list.Count() > 0) {
this.DataSource = list.ToList();
var sText = this.Items[0].ToString();
this.SelectionStart = txt.Length;
this.SelectionLength = sText.Length - txt.Length;
this.DroppedDown = true;
return;
} else {
this.DroppedDown = false;
this.SelectionStart = txt.Length;
}
}
}
private void SearchComboBox_Leave(object sender, EventArgs e) {
if (limitToList) {
if (!found || idTextBox.Text == defaultId) {
this.Text = "";
}
}
}
// Helpers
private ExpandoObject ToExpandoObject(object obj) {
IDictionary<string, object> newObj = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(obj.GetType())) {
newObj.Add(property.Name, property.GetValue(obj));
}
return (ExpandoObject)newObj;
}
private void ComboFill(IEnumerable<dynamic> dynObject, string valueField, string txtField = "") {
List<KeyValuePair<string, string>> cboList = new List<KeyValuePair<string, string>>();
if (dynObject != null && dynObject.Count() > 0) {
cboList.Add(new KeyValuePair<string, string>(defaultId, ""));
string dbFields = valueField;
if (txtField != "") { dbFields += "," + txtField; }
try {
foreach (dynamic item in dynObject) {
var changedItem = ToExpandoObject(item);
var dictItem = changedItem as IDictionary<string, object>;
string key = dictItem[valueField].ToString();
string value = key;
if (txtField != "") { value = dictItem[txtField].ToString(); }
cboList.Add(new KeyValuePair<string, string>(key, value));
}
} catch {
// Well dammit - something didn't work!
}
} else {
cboList.Add(new KeyValuePair<string, string>(valueField, txtField));
}
this.ValueMember = "key";
this.DisplayMember = "value";
this.DataSource = cboList;
}
public enum SearchComboBoxType {
Contains = 0,
StartOnly = 1,
EndOnly = 2
}
}
}
Hi Luca
With 2500 staff registering coming on / off shift at various times of the day at private locations across the country is there not a danger of running out of threads? I thought the aysnc handler made more efficient use of threads.
Does registering the handler as synchronised effectively achieve synchronisation of the token?
Value your thoughts
Ewan
Looks like I need to create and async hander to cope with the volume. Should be interesting as this is new territory for me!
Working on this. The original intended behavior was for DropDownStyle=Simple to result in a combobox to be dropped down on entering when in a cell but it’s not implemented. The DroppedDown property gets reset when the combo is reused for another cell.
There is no extra space. What you see is the result of subpixel rounding done by the browser. Check your window.devicePixelRatio. You can reproduce the same “effect” just with plain html and css: https://jsfiddle.net/je4pfoky/15/ And you can also find hundreds of posts related to this issue.
There is no solution to this problem in any environment. All you can do is use value multiples that may avoid rounding depending on the pixel ratio, which changes depending on the user’s device and the browser’s zoom value.
From the description I don’t think you need a background task. A background task is a thread that executes code and then ends or runs in a loop. It’s not something that is listening to requests. That’s a handler.
I would create an ashx handler and process the requests as they come in. The handler can obtain the key on first use and save it – remember to lock tje block that gets the key. If you mark the handler as reusable, the server will always use the same instance so you don’t even need statics.
It’s basically just a web service.
Hi Ewan,
The JSON objects you refer can be serialized/deserialized as strings. So you are looking for some way to share plain string.
There are several ways to share data among several sessions. Using Wisej you can use a static variable/property as explained in Global Variables thread.
Of course you can use database or some memory based cache like Redis.
HTH
Thank you for the sample.
Anchoring is currently not supported when hosted in a cell since there is no parent and the layout is managed by the client.
Docking is supported and works well.
AutoSize doesn’t seem to work because controls hosted in cells don’t have a parent. Will add a ticket. You can resolve it simply by adding Me.Size = Me.PreferredSize when you want the panel to autosize.
HTH
Hi Tiago
Thanks.
I realised that I didn’t need Reverse Geocode as the data returned is usually based on the centre of a post code.
If instead I get the Site manager to capture the Latitude and Longitude at the Site itself, I can use this as a basis for comparison, moving forwards.
Tests show it is far more accurate that just getting the coordinates for a post code.
I want to be able to establish that when staff register their arrival at the Site they are actually there.
Please post a reproducible test case. It depends on when you set the style, the row you are referring to may not exist anymore.
It’s normal behavior. The preview windows is a deep clone of dom elements, scaled down using css. The dom elements are rendered by the browser and the cache, etc.
Screen grabbing doesn’t exist in any browser. You either clone the elements or rebuild each one on a html5 canvas element usign drawing calls.
Hi Ewan,
Currently there is no support for Reverse Geoding in Web.Ext.GoogleMaps.GoogleMap
Support for Maps might change in the near future, following this thread about alternative maps libraries
I’ll register a feature request.
Hi Tiago
Yes I need to perform Reverse geocoding. Can a do this via the WiseJ Google Maps Extension?
Here it is.
Try scrolling to the maximum right.
Regards.
Take a look at this:
