I have an app built in Unity and setup to be released on the Mac App Store that has networking tasks that work just fine in an OS X build thats not for the app store but once a build that requires App store validation / codesign is made the networking fails. The app and the build process worked not that long ago but now fails.
I'm including networking permissions in the entitlements and I'm not seeing any trace of a sandbox error in the system Console. The in app purchase networking calls are succeeding, but if I check traffic for anything else in the terminal no data moves in or out.
So I was wondering if anyone had any ideas on what might be causing this or further tests I could use to figure out what the problem might be.
I never figured out what was wrong Unity's WWW class, but I was able to get around the issue using the System.Net.WebClient class. I implemented a simple wrapper that has a similar interface to Unity's WWW class. Here's the code I used:
using System;
using System.Net;
using System.Net.Security;
using System.Text;
/// <summary>
/// Web request using the WebClient class.
/// </summary>
/// <seealso cref="Assets.Scripts.WebRequest" />
internal class WebRequest
{
/// <summary>
/// The web client.
/// </summary>
private WebClient _client;
/// <summary>
/// The error message.
/// </summary>
private string _error;
/// <summary>
/// The is done flag.
/// </summary>
private bool _isDone;
/// <summary>
/// The progress.
/// </summary>
private float _progress;
/// <summary>
/// The text.
/// </summary>
private string _text;
/// <summary>
/// Initializes a new instance of the <see cref="WebRequest"/> class.
/// </summary>
/// <param name="url">The URL.</param>
public WebRequest(string url)
{
this._client = new System.Net.WebClient();
this._client.DownloadProgressChanged += this.WebClientProgressChanged;
this._client.DownloadStringCompleted += this.WebClientDownloadCompleted;
this._client.DownloadStringAsync(new Uri(url));
}
/// <summary>
/// Initializes a new instance of the <see cref="WebRequestDotNet"/> class.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="form">The form.</param>
public WebRequest(string url, UnityEngine.WWWForm form)
{
this._client = new System.Net.WebClient();
this._client.UploadProgressChanged += this.WebClientUploadProgressChanged;
this._client.UploadDataCompleted += this.WebClientUploadCompleted;
this._client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
// Try to get the header from the Unity form
foreach (var header in form.headers)
{
const string ContentType = "Content-Type";
if (header.Key == ContentType)
{
string contentType = header.Value;
this._client.Headers.Remove(ContentType);
this._client.Headers[ContentType] = contentType;
}
}
this._client.UploadDataAsync(new Uri(url), form.data);
}
/// <summary>
/// Gets the error message. Returns null if there is no error.
/// </summary>
/// <value>
/// The error message.
/// </value>
public string Error
{
get
{
return this._error;
}
}
/// <summary>
/// Gets a value indicating whether this request is done.
/// </summary>
/// <value>
/// <c>true</c> if this instance is done; otherwise, <c>false</c>.
/// </value>
public bool IsDone
{
get
{
return this._isDone;
}
}
/// <summary>
/// Gets the progress, 0 to 1.
/// </summary>
/// <value>
/// The progress.
/// </value>
public float Progress
{
get
{
return this._progress / 100.0f;
}
}
/// <summary>
/// Gets the resulting text.
/// </summary>
/// <value>
/// The text.
/// </value>
public string Text
{
get
{
return this._text;
}
}
/// <summary>
/// Called when the download is complete.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="DownloadStringCompletedEventArgs"/> instance containing the event data.</param>
private void WebClientDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
this._error = e.Error.ToString();
}
else
{
this._text = e.Result;
}
this._isDone = true;
}
/// <summary>
/// Called when the progress changes.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="DownloadProgressChangedEventArgs"/> instance containing the event data.</param>
private void WebClientProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this._progress += e.ProgressPercentage;
}
/// <summary>
/// Called when the upload is complete.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="UploadValuesCompletedEventArgs"/> instance containing the event data.</param>
private void WebClientUploadCompleted(object sender, UploadDataCompletedEventArgs e)
{
if (e.Error != null)
{
this._error = e.Error.ToString();
}
else
{
this._text = Encoding.UTF8.GetString(e.Result);
}
this._isDone = true;
}
/// <summary>
/// Called when the upload progress changes.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="UploadProgressChangedEventArgs"/> instance containing the event data.</param>
private void WebClientUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
this._progress += e.ProgressPercentage;
}
}
In latest version of Facebook C# SDk 6.4. Can we use FacebookSubscriptionVerify Action Method Attribute ? As this is not available in the FacebookClient Class
I was using the older version of Facebok C# SDK in my MVC3 project. Now, After switching to Facebook C# SDK 6.4 this class is not available.
Do we have any substitute for this?
I took a little more time this morning and confirmed that the attribute that you referenced was removed in version 6 (along with tons of other items). Since this project is open source, here is the code for the FacebookSubscriptionVerify ActionFilter that you used to use. For any references to functions within here that I did not include, this version on CodePlex has all of the code available for you to look at: http://facebooksdk.codeplex.com/SourceControl/changeset/view/08cb51f372b5#Source/Facebook.Web/FacebookSubscriptionsHttpHandler.cs
The new version (version 6.X) and the last few branches of version 5 can be found on the GitHub site - https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/tree/master/Source
With the availability of the source code, you should be able to, in tandem with how you were using this function, create your own ActionFilterAttribute that can replicate the functionality that you had previously.
// --------------------------------
// <copyright file="FacebookSubscriptionVerifyAttribute.cs" company="Thuzi LLC (www.thuzi.com)">
// Microsoft Public License (Ms-PL)
// </copyright>
// <author>Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)</author>
// <license>Released under the terms of the Microsoft Public License (Ms-PL)</license>
// <website>http://facebooksdk.codeplex.com</website>
// ---------------------------------
namespace Facebook.Web.Mvc
{
using System.Web.Mvc;
public class FacebookSubscriptionVerifyAttribute : ActionFilterAttribute
{
public string VerificationToken { get; set; }
public FacebookSubscriptionVerifyAttribute(string verificationToken)
{
VerificationToken = verificationToken;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.ContentType = "text/plain";
var request = filterContext.HttpContext.Request;
var modelState = filterContext.Controller.ViewData.ModelState;
string errorMessage;
if (request.HttpMethod == "GET")
{
if (string.IsNullOrEmpty(VerificationToken))
{
errorMessage = "Verification Token is empty.";
}
else
{
if (FacebookSubscriptionVerifier.VerifyGetSubscription(request, VerificationToken, out errorMessage))
{
return;
}
}
}
else
{
errorMessage = "Invalid http method.";
}
modelState.AddModelError("facebook-subscription", errorMessage);
filterContext.HttpContext.Response.StatusCode = 401;
}
}
}
And the code for the FacebookSubscriptionVerifier Class
namespace Facebook.Web
{
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web;
/// <summary>
/// Facebook helper methods for web.
/// </summary>
internal static class FacebookSubscriptionVerifier
{
internal const string HTTP_X_HUB_SIGNATURE_KEY = "HTTP_X_HUB_SIGNATURE";
internal static byte[] ComputeHmacSha1Hash(byte[] data, byte[] key)
{
Contract.Requires(data != null);
Contract.Requires(key != null);
Contract.Ensures(Contract.Result<byte[]>() != null);
using (var crypto = new System.Security.Cryptography.HMACSHA1(key))
{
return crypto.ComputeHash(data);
}
}
/// <summary>
/// Verify HTTP_X_HUB_SIGNATURE.
/// </summary>
/// <param name="secret">
/// The secret.
/// </param>
/// <param name="httpXHubSignature">
/// The http x hub signature.
/// </param>
/// <param name="jsonString">
/// The json string.
/// </param>
/// <returns>
/// Returns true if validation is successful.
/// </returns>
internal static bool VerifyHttpXHubSignature(string secret, string httpXHubSignature, string jsonString)
{
Contract.Requires(!string.IsNullOrEmpty(secret));
if (!string.IsNullOrEmpty(httpXHubSignature) && httpXHubSignature.StartsWith("sha1=") && httpXHubSignature.Length > 5 && !string.IsNullOrEmpty(jsonString))
{
// todo: test inner parts
var expectedSignature = httpXHubSignature.Substring(5);
var sha1 = ComputeHmacSha1Hash(Encoding.UTF8.GetBytes(jsonString), Encoding.UTF8.GetBytes(secret));
var hashString = new StringBuilder();
foreach (var b in sha1)
{
hashString.Append(b.ToString("x2"));
}
if (expectedSignature == hashString.ToString())
{
return true;
}
}
return false;
}
/// <summary>
/// Verify HTTP_X_HUB_SIGNATURE for http GET method.
/// </summary>
/// <param name="request">
/// The http request.
/// </param>
/// <param name="verifyToken">
/// The verify token.
/// </param>
/// <param name="errorMessage">
/// The error message.
/// </param>
/// <returns>
/// Returns true if successful otherwise false.
/// </returns>
internal static bool VerifyGetSubscription(HttpRequestBase request, string verifyToken, out string errorMessage)
{
Contract.Requires(request != null);
Contract.Requires(request.HttpMethod == "GET");
Contract.Requires(request.Params != null);
Contract.Requires(!string.IsNullOrEmpty(verifyToken));
errorMessage = null;
if (request.Params["hub.mode"] == "subscribe")
{
if (request.Params["hub.verify_token"] == verifyToken)
{
if (string.IsNullOrEmpty(request.Params["hub.challenge"]))
{
errorMessage = Properties.Resources.InvalidHubChallenge;
}
else
{
return true;
}
}
else
{
errorMessage = Properties.Resources.InvalidVerifyToken;
}
}
else
{
errorMessage = Properties.Resources.InvalidHubMode;
}
return false;
}
/// <summary>
/// Verify HTTP_X_HUB_SIGNATURE for http POST method.
/// </summary>
/// <param name="request">
/// The request.
/// </param>
/// <param name="secret">
/// The secret.
/// </param>
/// <param name="jsonString">
/// The json string.
/// </param>
/// <param name="errorMessage">
/// The error message.
/// </param>
/// <returns>
/// Returns true if successful otherwise false.
/// </returns>
internal static bool VerifyPostSubscription(HttpRequestBase request, string secret, string jsonString, out string errorMessage)
{
Contract.Requires(request != null);
Contract.Requires(request.HttpMethod == "POST");
Contract.Requires(request.Params != null);
Contract.Requires(!string.IsNullOrEmpty(secret));
errorMessage = null;
// signatures looks somewhat like "sha1=4594ae916543cece9de48e3289a5ab568f514b6a"
var signature = request.Params["HTTP_X_HUB_SIGNATURE"];
if (!string.IsNullOrEmpty(signature) && signature.StartsWith("sha1="))
{
var expectedSha1 = signature.Substring(5);
if (string.IsNullOrEmpty(expectedSha1))
{
errorMessage = Properties.Resources.InvalidHttpXHubSignature;
}
else
{
if (string.IsNullOrEmpty(jsonString))
{
errorMessage = Properties.Resources.InvalidJsonString;
return false;
}
var sha1 = ComputeHmacSha1Hash(Encoding.UTF8.GetBytes(jsonString), Encoding.UTF8.GetBytes(secret));
var hashString = new StringBuilder();
foreach (var b in sha1)
{
hashString.Append(b.ToString("x2"));
}
if (expectedSha1 == hashString.ToString())
{
// todo: test
return true;
}
// todo: test
errorMessage = Properties.Resources.InvalidHttpXHubSignature;
}
}
else
{
errorMessage = Properties.Resources.InvalidHttpXHubSignature;
}
return false;
}
}
}
I have been researching for quite a while now for an appropriate spell checker for textbox and multiline textbox.
I can see that this functionality is built in for firefox but its not present in chrome.
I was checking out all the demos for spellcheck which is provided by
jquery spellchecker - badsyntax and i find it really nice and useful.
here is the link
http://jquery-spellchecker.badsyntax.co/
But my problem here is- spellchecker makes use of php webservices and i want to use it in my ASP.net Webapplication.
is there any work around so that i can run it using asp.net web services?
Please provide me with a solution.
I'm the author of the plugin and would really like to incorporate some other webservice implementations.
This popped up recently in my google alerts, I can't verify it works though:
http://www.yodotnet.com/post/2013/02/24/Jquery-Spellchecker-for-NET.aspx
https://github.com/AnthonyTerra/ASP.MVC-Jquery-Spellchecker
Hi Guys: Veerendra Prabhu, badsyntax; I've integrated Nhunspell and asp.net Web Service (.asmx) and currently I'm trying to integrate jquery spellchecker - badsyntax to the proyect, I'm jquery spellchecker now conects with my web services but Im still dealing whith the returned data type of my web service to allow jquery spellcheker does its magic, but I thinks its something.
I took ideas from:
deepinthecode.com
Here are some ideas that I used:
I used NHusnpell that helps to get the incorrect words within a passed text and look into the dictionary (open office downloaded as .oxt but you have to chante to zip to get en_US.aff, and en_US.dic) this files needs to be at bin directory.
At Glabal.asax file I created a static instance of NHuspell that does all the work.
public class Global : System.Web.HttpApplication
{
static SpellEngine spellEngine;
static public SpellEngine SpellEngine { get { return spellEngine; } }
protected void Application_Start(object sender, EventArgs e)
{
try
{
string dictionaryPath = Server.MapPath("Bin") + "\\";
Hunspell.NativeDllPath = dictionaryPath;
spellEngine = new SpellEngine();
LanguageConfig enConfig = new LanguageConfig();
enConfig.LanguageCode = "en";
enConfig.HunspellAffFile = dictionaryPath + "en_us.aff";
enConfig.HunspellDictFile = dictionaryPath + "en_us.dic";
enConfig.HunspellKey = "";
//enConfig.HyphenDictFile = dictionaryPath + "hyph_en_us.dic";
spellEngine.AddLanguage(enConfig);
}
catch (Exception ex)
{
if (spellEngine != null)
spellEngine.Dispose();
}
}
...
protected void Application_End(object sender, EventArgs e)
{
if (spellEngine != null)
spellEngine.Dispose();
spellEngine = null;
}
}
Then I created an ASMX web service for the Get_Incorrect_Words and Get_Suggestions methods
/// <summary>
/// Summary description for SpellCheckerService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService()]
public class SpellCheckerService : System.Web.Services.WebService
{
[WebMethod]
//[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string get_incorrect_words(string words)
{
Dictionary<string, string> IncorrectWords = new Dictionary<string, string>();
List<string> wrongWords = new List<string>();
var palabras = words.Split(' ');
// Check spelling of each word that has been passed to the method
foreach (string word in palabras)
{
bool correct = Global.SpellEngine["en"].Spell(word);
if (!correct){
wrongWords.Add(word);
}
}
IncorrectWords.Add("data", wrongWords[0]);
return wrongWords[0];
}
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public List<string> get_suggestions(string word)
{
List<string> suggestions = new List<string>();
suggestions = Global.SpellEngine["en"].Suggest(word);
suggestions.Sort();
return suggestions;
}
And Finally I modified the calls to the get_incorrect_words and get_suggestions in jquery.Spellchecker.js
/* Config
*************************/
var defaultConfig = {
lang: 'en',
webservice: {
path: 'SpellCheckerService.asmx/get_incorrect_words'
//,driver: 'LabNET'
},
local: {
requestError: 'There was an error processing the request.',
ignoreWord: 'Ignore word',
ignoreAll: 'Ignore all',
ignoreForever: 'Add to dictionary',
loading: 'Loading...',
noSuggestions: '(No suggestions)'
},
suggestBox: {
numWords: 5,
position: 'above',
offset: 2,
appendTo: null
},
incorrectWords: {
container: 'body', //selector
position: null //function
}
};
var pluginName = 'spellchecker';
...
/* Spellchecker web service
*************************/
var WebService = function(config) {
this.config = config;
this.defaultConfig = {
url: config.webservice.path,
//contentType: "application/json; charset=utf-8",
type: 'POST',
dataType: 'text',
cache: false,
data: JSON.stringify({
lang: config.lang,
driver: config.webservice.driver
}, null,2) ,
error: function() {
alert(config.local.requestError);
}.bind(this)
};
};
WebService.prototype.makeRequest = function(config) {
var defaultConfig = $.extend(true, {}, this.defaultConfig);
return $.ajax($.extend(true, defaultConfig, config));
};
WebService.prototype.checkWords = function (text, callback) {
//action: 'get_incorrect_words',
//JSON.stringify({
// text: text
//}, null, 2)
return this.makeRequest(
{
data: { words: text },
success: callback
});
};
WebService.prototype.getSuggestions = function (word, callback) {
//action: 'get_suggestions',
return this.makeRequest({
data: JSON.stringify({
word: word
}, null, 2),
success: callback
});
};
I have found a solution for the issue and
below is the webservice which returns the JSON response for the jquery spell checker
This code is the modified verion of code found in
github.com/jackmyang/jQuery-Spell-Checker-for-ASP.NET
/// <summary>
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
< %# WebHandler Language="C#" Class="JQuerySpellCheckerHandler2" %>
/// <summary>
/// jQuery spell checker http handler class. Original server-side code was written by Richard Willis in PHP.
/// This is a version derived from the original design and implemented for ASP.NET platform.
///
/// It's very easy to use this handler with ASP.NET WebForm or MVC. Simply do the following steps:
/// 1. Include project jquery.spellchecker assembly in the website as a reference
/// 2. Include the httphandler node in the system.web node for local dev or IIS 6 or below
/// <example>
/// <![CDATA[
/// <system.web>
/// <httpHandlers>
/// <add verb="GET,HEAD,POST" type="jquery.spellchecker.JQuerySpellCheckerHandler" path="JQuerySpellCheckerHandler.ashx"/>
/// </httpHandlers>
/// </system.web>
/// ]]>
/// </example>
/// 3. If IIS7 is the target web server, also need to include the httphandler node in the system.webServer node
/// <example>
/// <![CDATA[
/// <system.webServer>
/// <handlers>
/// <add verb="GET,HEAD,POST" name="JQuerySpellCheckerHandler" type="jquery.spellchecker.JQuerySpellCheckerHandler" path="JQuerySpellCheckerHandler.ashx"/>
/// </handlers>
/// </system.webServer>
/// ]]>
/// </example>
/// 4. On the web page which included the spell checker, set the 'url' property to '~/JQuerySpellCheckerHandler.ashx'
/// <example>
/// <![CDATA[
/// $("#text-content")
/// .spellchecker({
/// url: "~/JQuerySpellCheckerHandler.ashx",
/// lang: "en",
/// engine: "google",
/// suggestBoxPosition: "above"
/// })
/// ]]>
/// </example>
/// </summary>
/// <remarks>
/// Manipulations of XmlNodeList is used for compatibility concern with lower version of .NET framework,
/// alternatively, they can be simplified using 'LINQ for XML' if .NET 3.5 or higher is available.
/// </remarks>
public class JQuerySpellCheckerHandler2 : IHttpHandler
{
#region fields
// in case google changes url, value of GoogleSpellCheckRpc can be stored in web.config instead to avoid code re-compilation
private const string GoogleSpellCheckRpc = "https://www.google.com/tbproxy/spell?";
private const string GoogleFlagTextAlreadClipped = "textalreadyclipped";
private const string GoogleFlagIgnoreDups = "ignoredups";
private const string GoogleFlagIgnoreDigits = "ignoredigits";
private const string GoogleFlagIgnoreAllCaps = "ignoreallcaps";
#endregion
#region properties
/// <summary>
/// Gets or sets a value indicating whether [ignore duplicated words].
/// </summary>
/// <value><c>true</c> if [ignore dups]; otherwise, <c>false</c>.</value>
private bool IgnoreDups { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [ignore digits].
/// </summary>
/// <value><c>true</c> if [ignore digits]; otherwise, <c>false</c>.</value>
private bool IgnoreDigits { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [ignore all capitals].
/// </summary>
/// <value><c>true</c> if [ignore all caps]; otherwise, <c>false</c>.</value>
private bool IgnoreAllCaps { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [text alread clipped].
/// </summary>
/// <value><c>true</c> if [text alread clipped]; otherwise, <c>false</c>.</value>
private bool TextAlreadClipped { get; set; }
#endregion
#region Implementation of IHttpHandler
/// <summary>
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
/// </summary>
/// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.
/// </param>
public void ProcessRequest(HttpContext context)
{
string engine = context.Request.Form[1];
string lang = context.Request.Form["lang"];
string text = context.Request.Form[3];
string suggest = context.Request.Form[2];
SetSwitches(context);
string result = SpellCheck(text, lang, engine, suggest);
context.Response.ContentType = "application/js";
string jsonStr = "{\"outcome\":\"success\",\"data\":[" + result + "]}";
if (suggest == "get_incorrect_words")
{
context.Response.Write(jsonStr);
}
else
{
context.Response.Write(result);
}
}
/// <summary>
/// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
/// </summary>
/// <returns>
/// true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.
/// </returns>
public bool IsReusable
{
get { return false; }
}
#endregion
#region private methods
/// <summary>
/// Spells the check.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="lang">The lang.</param>
/// <param name="engine">The engine.</param>
/// <param name="suggest">The suggest.</param>
/// <returns></returns>
private string SpellCheck(string text, string lang, string engine, string suggest)
{
if (0 == string.Compare(suggest, "undefined", StringComparison.OrdinalIgnoreCase))
{
suggest = string.Empty;
}
if (0 != string.Compare(engine, "google", true))
{
throw new NotImplementedException("Only google spell check engine is support at this moment.");
}
string xml;
List<string> result;
if (string.IsNullOrEmpty(suggest) || suggest == "get_incorrect_words")
{
xml = GetSpellCheckRequest(text, lang);
result = GetListOfMisspelledWords(xml, text);
}
else
{
xml = GetSpellCheckRequest(text, lang);
result = GetListOfSuggestWords(xml, text);
}
return ConvertStringListToJavascriptArrayString(result);
}
/// <summary>
/// Sets the boolean switch.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="queryStringParameter">The query string parameter.</param>
/// <returns></returns>
private static bool SetBooleanSwitch(HttpContext context, string queryStringParameter)
{
byte tryParseZeroOne;
string queryStringValue = context.Request.QueryString[queryStringParameter];
if (!string.IsNullOrEmpty(queryStringValue) && byte.TryParse(queryStringValue, out tryParseZeroOne))
{
if (1 < tryParseZeroOne || 0 > tryParseZeroOne)
{
throw new InvalidOperationException(string.Format("Query string parameter '{0}' only supports values of 1 and 0.", queryStringParameter));
}
return tryParseZeroOne == 1;
}
return false;
}
/// <summary>
/// Gets the list of suggest words.
/// </summary>
/// <param name="xml">The source XML.</param>
/// <param name="suggest">The word to be suggested.</param>
/// <returns></returns>
private static List<string> GetListOfSuggestWords(string xml, string suggest)
{
if (string.IsNullOrEmpty(xml) || string.IsNullOrEmpty(suggest))
{
return null;
}
//
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xml);
if (!xdoc.HasChildNodes)
{
return null;
}
XmlNodeList nodeList = xdoc.SelectNodes("//c");
if (null == nodeList || 0 >= nodeList.Count)
{
return null;
}
List<string> list = new List<string>();
foreach (XmlNode node in nodeList)
{
list.AddRange(node.InnerText.Split('\t'));
return list;
}
return list;
}
/// <summary>
/// Gets the list of misspelled words.
/// </summary>
/// <param name="xml">The source XML.</param>
/// <param name="text">The text.</param>
/// <returns></returns>
private static List<string> GetListOfMisspelledWords(string xml, string text)
{
if (string.IsNullOrEmpty(xml) || string.IsNullOrEmpty(text))
{
return null;
}
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(xml);
if (!xdoc.HasChildNodes)
{
return null;
}
XmlNodeList nodeList = xdoc.SelectNodes("//c");
if (null == nodeList || 0 >= nodeList.Count)
{
return null;
}
List<string> list = new List<string>();
foreach (XmlNode node in nodeList)
{
int offset = Convert.ToInt32(node.Attributes["o"].Value);
int length = Convert.ToInt32(node.Attributes["l"].Value);
list.Add(text.Substring(offset, length));
}
return list;
}
/// <summary>
/// Constructs the request URL.
/// </summary>
/// <param name="text">The text which may contain multiple words.</param>
/// <param name="lang">The language.</param>
/// <returns></returns>
private static string ConstructRequestUrl(string text, string lang)
{
if (string.IsNullOrEmpty(text))
{
return string.Empty;
}
lang = string.IsNullOrEmpty(lang) ? "en" : lang;
return string.Format("{0}lang={1}&text={2}", GoogleSpellCheckRpc, lang, text);
}
/// <summary>
/// Converts the C# string list to Javascript array string.
/// </summary>
/// <param name="list">The list.</param>
/// <returns></returns>
private static string ConvertStringListToJavascriptArrayString(ICollection<string> list)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("[");
if (null != list && 0 < list.Count)
{
bool showSeperator = false;
foreach (string word in list)
{
if (showSeperator)
{
stringBuilder.Append(",");
}
stringBuilder.AppendFormat("\"{0}\"", word);
showSeperator = true;
}
}
stringBuilder.Append("]");
return stringBuilder.ToString();
}
/// <summary>
/// Sets the switches.
/// </summary>
/// <param name="context">The context.</param>
private void SetSwitches(HttpContext context)
{
IgnoreAllCaps = SetBooleanSwitch(context, GoogleFlagIgnoreAllCaps);
IgnoreDigits = SetBooleanSwitch(context, GoogleFlagIgnoreDigits);
IgnoreDups = SetBooleanSwitch(context, GoogleFlagIgnoreDups);
TextAlreadClipped = SetBooleanSwitch(context, GoogleFlagTextAlreadClipped);
}
/// <summary>
/// Requests the spell check and get the result back.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="lang">The language.</param>
/// <returns></returns>
private string GetSpellCheckRequest(string text, string lang)
{
string requestUrl = ConstructRequestUrl(text, lang);
string requestContentXml = ConstructSpellRequestContentXml(text);
byte[] buffer = Encoding.UTF8.GetBytes(requestContentXml);
WebClient webClient = new WebClient();
webClient.Headers.Add("Content-Type", "text/xml");
try
{
byte[] response = webClient.UploadData(requestUrl, "POST", buffer);
return Encoding.UTF8.GetString(response);
}
catch (ArgumentException)
{
return string.Empty;
}
}
/// <summary>
/// Constructs the spell request content XML.
/// </summary>
/// <param name="text">The text which may contain multiple words.</param>
/// <returns></returns>
private string ConstructSpellRequestContentXml(string text)
{
XmlDocument doc = new XmlDocument(); // Create the XML Declaration, and append it to XML document
XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", null, null);
doc.AppendChild(declaration);
XmlElement root = doc.CreateElement("spellrequest");
root.SetAttribute(GoogleFlagTextAlreadClipped, TextAlreadClipped ? "1" : "0");
root.SetAttribute(GoogleFlagIgnoreDups, IgnoreDups ? "1" : "0");
root.SetAttribute(GoogleFlagIgnoreDigits, IgnoreDigits ? "1" : "0");
root.SetAttribute(GoogleFlagIgnoreAllCaps, IgnoreAllCaps ? "1" : "0");
doc.AppendChild(root);
XmlElement textElement = doc.CreateElement("text");
textElement.InnerText = text;
root.AppendChild(textElement);
return doc.InnerXml;
}
#endregion
}
Also you can use this javascript:
// Replace the Spellchecker.php path with Asp.net ashx path
spellchecker = new $.SpellChecker(body, {
lang: 'en',
parser: 'html',
webservice: {
path: "../Includes/JS/spellify/JQuerySpellCheckerHandler2.ashx",
driver: 'google'
},
suggestBox: {
position: 'below'
}
});
// Bind spellchecker handler functions
spellchecker.on('check.success', function() {
alert('There are no incorrectly spelt words.');
});
spellchecker.check();
I'd like to use a designer (e.g. Expression Blend) to template the LongListSelector control (from the SL toolkit for WP7), but I can't figure out how to format the data to fit what this control expects.
Any pointers to a tutorial would be appreciated. Thanks.
Use a specialized collection, like this:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Collections.ObjectModel;
namespace Stackoverflow.Collections
{
/// <summary>
/// Represents a specialized collection to integrate with the
/// <see cref="Microsoft.Phone.Controls.LongListSelector"/> control.
/// </summary>
/// <typeparam name="T">The type of the values in the collection.</typeparam>
/// <typeparam name="TKey">The type of the keys in the collection.</typeparam>
public class LongListCollection<T, TKey> : ObservableCollection<LongListItem<T, TKey>>
where T : IComparable<T>
where TKey : IComparable<TKey>
{
/// <summary>
/// The key selector for adding items.
/// </summary>
private Func<T, TKey> keySelector;
/// <summary>
/// Initializes a new instance of the <see cref="LongListCollection<T, TKey>"/> class.
/// </summary>
/// <param name="keySelector">The key selector.</param>
public LongListCollection(Func<T, TKey> keySelector)
{
if (keySelector == null)
throw new ArgumentNullException("keySelector");
this.keySelector = keySelector;
}
/// <summary>
/// Initializes a new instance of the <see cref="LongListCollection<T, TKey>"/> class.
/// </summary>
/// <param name="keySelector">The key selector.</param>
/// <param name="items">A initial collection.</param>
public LongListCollection(Func<T, TKey> keySelector, IEnumerable<T> items)
{
if (keySelector == null)
throw new ArgumentNullException("keySelector");
if (items == null)
throw new ArgumentNullException("items");
this.keySelector = keySelector;
var groups = new Dictionary<TKey, LongListItem<T, TKey>>();
foreach (var item in items.OrderBy(x => x))
{
var key = keySelector(item);
if (groups.ContainsKey(key) == false)
groups.Add(key, new LongListItem<T, TKey>(key));
groups[key].Add(item);
}
foreach (var value in groups.Values)
this.Add(value);
}
/// <summary>
/// Adds the specified item to the collection.
/// </summary>
/// <param name="item">The item.</param>
public void Add(T item)
{
TKey key = keySelector(item);
var group = this.FirstOrDefault(x => x.Key.Equals(key));
if (group != null)
group.Add(item);
else
this.Add(new LongListItem<T, TKey>(key) { item });
}
/// <summary>
/// Inserts an item into the collection at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which item should be inserted.</param>
/// <param name="item">The object to insert.</param>
protected override void InsertItem(int index, LongListItem<T, TKey> item)
{
for (int i = 0; i < this.Count; i++)
{
switch (Math.Sign(this[i].CompareTo(item)))
{
case 0:
throw new InvalidOperationException("Cannot insert duplicated items.");
case 1:
base.InsertItem(i, item);
return;
case -1:
break;
}
}
base.InsertItem(this.Count, item);
}
}
/// <summary>
/// Represents a specialized data structure to integrate with the
/// <see cref="Microsoft.Phone.Controls.LongListSelector"/> control.
/// </summary>
/// <typeparam name="T">The type of the values in the structure.</typeparam>
/// <typeparam name="TKey">The type of the key in the structure.</typeparam>
public class LongListItem<T, TKey> : ObservableCollection<T>, IComparable<LongListItem<T, TKey>>
where T : IComparable<T>
where TKey : IComparable<TKey>
{
/// <summary>
/// Initializes a new instance of the <see cref="LongListItem<T, TKey>"/> class.
/// </summary>
public LongListItem()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LongListItem<T, TKey>"/> class.
/// </summary>
/// <param name="key">The item's key.</param>
public LongListItem(TKey key)
{
this.Key = key;
}
/// <summary>
/// Gets or sets the item key.
/// </summary>
/// <value>The item key.</value>
public TKey Key
{
get;
set;
}
/// <summary>
/// Gets a value indicating whether this instance has any items.
/// </summary>
/// <value><c>true</c> if this instance has any items; otherwise, <c>false</c>.</value>
public bool HasItems
{
get
{
return Count > 0;
}
}
/// <summary>
/// Inserts an item into the collection at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which item should be inserted.</param>
/// <param name="item">The object to insert.</param>
protected override void InsertItem(int index, T item)
{
for (int i = 0; i < this.Count; i++)
{
switch (Math.Sign(this[i].CompareTo(item)))
{
case 0:
return;
case 1:
base.InsertItem(i, item);
return;
case -1:
break;
}
}
base.InsertItem(this.Count, item);
}
/// <summary>
/// Compares to.
/// </summary>
/// <param name="other">The other.</param>
/// <returns></returns>
public int CompareTo(LongListItem<T, TKey> other)
{
if (other == null)
return 1;
return this.Key.CompareTo(other.Key);
}
}
}
I blogged a step-by-step guide;
http://pauliom.com/2013/02/03/how-to-use-blend-sample-data-with-a-longlistselector/
Does anyone came across a problem when you have a Class that inherits from Forms and then have all the forms inherit from Class, and then tried to load the form in design mode in visual studio? Does it loads correctly, because on mine it shows "Illegal characters in path.".
I ran the visual studio in debug mode and found that it is try to check a path for the file I suppose and gets the ´>´ of the generic definition.
So is it possible to implement generics over windows forms or do I have to get a workaround for this, I have searched the internet for some examples or clues where to follow but could find any important one. Any pointers would be much appreciated, because the application works runs fine but not the design mode of visual studio.
Thanks.
Base class
public class BaseForm<T, TU> : Form, IFormLanguageStrings
where T : class
where TU : class
{
#region Variables
public IApplicationValues applicationValues;
public T businessObject;
public IEventBroker eventBroker;
private bool hasChangesToCommit = false;
public ILanguageManager languageManager;
public IMessageBox messageBox;
public TU objService;
public DatabaseOperationType operationType;
public event EventHandler OnNeedToCommitChanges;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="BaseForm"/> class.
/// </summary>
public BaseForm()
{
Closing += BaseForm_Closing;
Load += BaseForm_Load;
if (IsInDesignMode) return;
SetService();
}
#endregion
#region Form Events
/// <summary>
/// Handles the Load event of the BaseForm control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void BaseForm_Load(object sender, EventArgs e)
{
if (IsInDesignMode) return;
SetLabels();
SetControls();
LoadCombos();
LoadDataForForm();
ValidateDataInput();
if (operationType == DatabaseOperationType.View)
{
eventBroker.Unregister(this);
DisableAllControls();
InvisibleSelectControls("BtnAction");
}
}
/// <summary>
/// Handles the Closing event of the BaseForm control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.ComponentModel.CancelEventArgs"/> instance containing the event data.</param>
private void BaseForm_Closing(object sender, CancelEventArgs e)
{
if (hasChangesToCommit)
{
if (
messageBox.ShowQuestion(languageManager.GetString("MSG_PerformPendingOperations"),
MessageBoxButton.YesNo, MessageBoxResult.No) == MessageBoxResult.Yes)
{
RaiseCommitChanges();
}
}
if (eventBroker != null)
eventBroker.Unregister(this);
}
#endregion
#region Virtual Methods
/// <summary>
/// Sets the labels.
/// </summary>
public virtual void SetLabels()
{
Controls.All().OfType<Control>().ToList().ForEach(
ctl =>
{
if (!string.IsNullOrEmpty(ctl.Name))
{
string label = languageManager.GetString(ctl.Name);
if (!string.IsNullOrEmpty(label))
{
ctl.Text = label;
}
if (ctl is ElementHost)
{
if (((ElementHost) ctl).Child is IFormLanguageStrings)
{
(((ElementHost) ctl).Child as IFormLanguageStrings).SetLabels();
}
}
}
});
}
/// <summary>
/// Sets the service.
/// </summary>
public virtual void SetService()
{
applicationValues = ServiceGateway.GetService<IApplicationValues>();
languageManager = ServiceGateway.GetService<ILanguageManager>();
messageBox = ServiceGateway.GetService<IMessageBox>();
eventBroker = ServiceGateway.GetService<IEventBroker>();
eventBroker.Register(this);
objService = ServiceGateway.GetService<TU>();
}
/// <summary>
/// Validates the data input.
/// </summary>
public virtual void ValidateDataInput()
{
}
/// <summary>
/// Determines whether [has to commit changes] [the specified commit].
/// </summary>
/// <param name="commit">if set to <c>true</c> [commit].</param>
public virtual void HasToCommitChanges(bool commit)
{
switch (operationType)
{
case DatabaseOperationType.Update:
hasChangesToCommit = commit;
break;
}
}
/// <summary>
/// Loads the combos.
/// </summary>
public virtual void LoadCombos()
{
}
/// <summary>
/// Loads the data for form.
/// </summary>
public virtual void LoadDataForForm()
{
}
/// <summary>
/// Sets the controls.
/// </summary>
public virtual void SetControls()
{
}
#endregion
#region Private Methods
/// <summary>
/// Raises the commit changes.
/// </summary>
private void RaiseCommitChanges()
{
if (OnNeedToCommitChanges != null)
{
OnNeedToCommitChanges(this, EventArgs.Empty);
}
}
/// <summary>
/// Closes the form.
/// </summary>
protected void CloseForm()
{
FireEventBroker(EventTopics.CloseMdiChild, new CloseMdiChildEventArgs(this));
}
/// <summary>
/// Enables or disable controls.
/// </summary>
/// <typeparam name="T">type of control</typeparam>
/// <param name="isEnable">if set to <c>true</c> [is enable].</param>
private void EnableDisableControls<TX>(bool isEnable) where TX : Control
{
Controls.All()
.OfType<TX>()
.ToList()
.ForEach(ctl => ctl.Enabled = isEnable);
}
/// <summary>
/// Visibles or invisible all controls.
/// </summary>
/// <param name="isVisible">if set to <c>true</c> [is visible].</param>
private void VisibleInvisibleAllControls(bool isVisible)
{
Controls.All()
.OfType<Control>()
.ToList()
.ForEach(ctl => ctl.Visible = isVisible);
}
#endregion
#region Public Methods
/// <summary>
/// Gets a value indicating whether this instance is in design mode.
/// </summary>
/// <value>
/// <c>true</c> if this instance is in design mode; otherwise, <c>false</c>.
/// </value>
public bool IsInDesignMode
{
get { return (Process.GetCurrentProcess().ProcessName == "devenv"); }
}
/// <summary>
/// Fires the event broker.
/// </summary>
/// <param name="eventTopic">The event topic.</param>
/// <param name="eventArgs">The <see cref="System.EventArgs"/> instance containing the event data.</param>
public void FireEventBroker(string eventTopic, EventArgs eventArgs)
{
eventBroker.Fire(eventTopic, this, eventArgs);
}
/// <summary>
/// Clears all bindings.
/// </summary>
public void ClearAllBindings()
{
Controls.All().OfType<Control>().ToList().ForEach(
ctl => { if (ctl.DataBindings.Count != 0) ctl.DataBindings.Clear(); });
}
/// <summary>
/// Enables all controls.
/// </summary>
public void EnableAllControls()
{
EnableDisableAllControls(true);
}
/// <summary>
/// Disables all controls.
/// </summary>
public void DisableAllControls()
{
EnableDisableAllControls(false);
}
/// <summary>
/// Enables or disable all controls.
/// </summary>
/// <param name="isEnable">if set to <c>true</c> [is enable].</param>
private void EnableDisableAllControls(bool isEnable)
{
Controls.All()
.OfType<Control>()
.ToList()
.ForEach(ctl => ctl.Enabled = isEnable);
}
/// <summary>
/// Enables all buttons.
/// </summary>
public void EnableAllButtons()
{
EnableDisableControls<Button>(true);
}
/// <summary>
/// Disables all buttons.
/// </summary>
public void DisableAllButtons()
{
EnableDisableControls<Button>(false);
}
/// <summary>
/// Enables all text boxes.
/// </summary>
public void EnableAllTextBoxes()
{
EnableDisableControls<TextBox>(true);
}
/// <summary>
/// Disables all text boxes.
/// </summary>
public void DisableAllTextBoxes()
{
EnableDisableControls<TextBox>(false);
}
/// <summary>
/// Enables the select controls.
/// </summary>
/// <param name="controlNames">The control names.</param>
public void EnableSelectControls(params string[] controlNames)
{
EnableDisableSelectedControls(true, controlNames);
}
/// <summary>
/// Disables the select controls.
/// </summary>
/// <param name="controlNames">The control names.</param>
public void DisableSelectControls(params string[] controlNames)
{
EnableDisableSelectedControls(false, controlNames);
}
/// <summary>
/// Enables or disable selected controls.
/// </summary>
/// <param name="isEnable">if set to <c>true</c> [is enable].</param>
/// <param name="controlNames">The control names.</param>
public void EnableDisableSelectedControls(bool isEnable, params string[] controlNames)
{
Controls.All()
.OfType<Control>()
.ToList()
.ForEach(ctl => { if (controlNames.Contains(ctl.Name)) ctl.Enabled = isEnable; });
}
/// <summary>
/// Visibles the select controls.
/// </summary>
/// <param name="controlNames">The control names.</param>
public void VisibleSelectControls(params string[] controlNames)
{
VisibleInvisibleSelectedControls(true, controlNames);
}
/// <summary>
/// Invisibles the select controls.
/// </summary>
/// <param name="controlNames">The control names.</param>
public void InvisibleSelectControls(params string[] controlNames)
{
VisibleInvisibleSelectedControls(false, controlNames);
}
/// <summary>
/// Visibles or invisible selected controls.
/// </summary>
/// <param name="isVisible">if set to <c>true</c> [is visible].</param>
/// <param name="controlNames">The control names.</param>
private void VisibleInvisibleSelectedControls(bool isVisible, params string[] controlNames)
{
Controls.All()
.OfType<Control>()
.ToList()
.ForEach(ctl => { if (controlNames.Contains(ctl.Name)) ctl.Visible = isVisible; });
}
/// <summary>
/// Visibles all controls.
/// </summary>
public void VisibleAllControls()
{
VisibleInvisibleAllControls(true);
}
/// <summary>
/// Invisibles all controls.
/// </summary>
public void InvisibleAllControls()
{
VisibleInvisibleAllControls(false);
}
#endregion
}
}
Ok so problem is that for "MyForm" designer doesn't work:
public class MyForm : BaseForm<MyPresenter, MyView>
{
//designer doesn't work
}
Workaround for this is to create helper class:
public class MyFormWithDesign : BaseForm<MyPresenter, MyView>
{
//designer doesn't work
}
so we derive from helper class and not from generic class:
public class MyForm : MyFormWithDesign
{
//designer WORKS!
}
Additional details about the problem can be found here:
Windows Form Designer can't use a component derived from a generic class