All Answers

0 votes

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.

 

  • Luca answered Jul 30, 2018 - 2:51 pm
0 votes

Hi Darren,

You are right. Logged as WJ9101

0 votes

Hi Kevin,

Did you try it running Wisej 1.5.9?

0 votes

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?

0 votes

Hi Tung Ngo,

Can you attach a sample reproducing the issue?

0 votes
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
        }
    }
}
  • Kevin Caine answered Jul 29, 2018 - 10:30 am
  • last active Jul 29, 2018 - 11:16 am
0 votes

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

0 votes

Looks like I need to create and async hander to cope with the volume. Should be interesting as this is new territory for me!

 

0 votes

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.

  • Luca answered Jul 28, 2018 - 7:07 pm
0 votes

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.

  • Luca answered Jul 28, 2018 - 7:05 pm
0 votes

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.

  • Luca answered Jul 28, 2018 - 4:57 pm
0 votes

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

0 votes

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

  • Luca answered Jul 28, 2018 - 3:24 pm
0 votes

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.

0 votes

Please post a reproducible test case. It depends on when you set the style, the row you are referring to may not exist anymore.

  • Luca answered Jul 28, 2018 - 2:01 am
0 votes

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.

 

  • Luca answered Jul 28, 2018 - 1:57 am
0 votes

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.

 

0 votes

Hi Tiago

Yes I need to perform Reverse geocoding. Can a do this via the WiseJ Google Maps Extension?

0 votes

Here it is.

Try scrolling to the maximum right.

Regards.

0 votes
Showing 7021 - 7040 of 11k results