On Safari browser I need to select an Option from the dropdown but the funny thing is that it works for all the browsers except for Safari on Mac OS.
I am using Safari 10.0.3 with selenium webdriver version 3.3.0
I have written the code in C#. Refer the code below -
IWebDriver driver;
driver = new SafariDriver();
List<string> handles = driver.WindowHandles.ToList<string>();
driver.SwitchTo().Window(handles.First());
driver.Navigate().GoToUrl("https://myip/MyPage.aspx");
SelectElement element = new SelectElement(driver.FindElement(By.Id("securityQuestion")));
int totalOptions = element.Options.Count;
Random rnd = new Random();
int rndValue = rnd.Next(1, totalOptions);
element.SelectByIndex(rndValue); // This is not working for Safari browser
driver.FindElement(By.Id("securityAnswer")).SendKeys("test");
driver.FindElement(By.Id("ctl00_Content_btnNext")).Click();
driver.Close();
No error is thrown just that it doesnt select any value from the dropdown.
This is a safaridriver bug. The fix is in WebKit, and being tracked here:
https://bugs.webkit.org/show_bug.cgi?id=174710
As a workaround, you can modify which options of a select are selected using JavaScript and the DOM API.
Try this sample here for JS workaround - implemented as C# extension. This code works on Safari (tested on version 10.1+).
This is not the complete code, just a snippet to make it simple. You can extend it to support any functionality you like.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Internal;
using OpenQA.Selenium.Support.UI;
namespace Gravity.Plugins.Actions.Extensions
{
public static class SelectExtensions
{
/// <summary>
/// Select the option by the index, as determined by the "index" attribute of the
/// element.
/// </summary>
/// <param name="selectElement">This <see cref="SelectElement"/>.</param>
/// <param name="index">The value of the index attribute of the option to be selected.</param>
public static void JsSelectByIndex(this SelectElement selectElement, int index)
{
// constants
var script = $"options[{index}].selected = true;";
// web element to act on
var onElement = selectElement.WrappedElement;
var onDriver = (IWrapsDriver)onElement;
// execute
((IJavaScriptExecutor)onDriver).ExecuteScript(script, onElement);
}
/// <summary>
/// Select all options by the text displayed.
/// </summary>
/// <param name="selectElement">This <see cref="SelectElement"/>.</param>
/// <param name="text">The text of the option to be selected.</param>
public static void JsSelectByText(this SelectElement selectElement, string text)
{
// constants
var script =
"var options = arguments[0].getElementsByTagName('option');" +
"" +
"for(i = 0; i < options.length; i++) {" +
$" if(options[i].innerText !== '{text}') {{" +
" continue;" +
" }" +
" options[i].selected = true;" +
" break;" +
"}";
// web element to act on
var onElement = selectElement.WrappedElement;
var onDriver = (IWrapsDriver)onElement;
// execute
((IJavaScriptExecutor)onDriver).ExecuteScript(script, onElement);
}
/// <summary>
/// Select an option by the value.
/// </summary>
/// <param name="selectElement"></param>
/// <param name="value">The value of the option to be selected.</param>
public static void JsSelectByValue(this SelectElement selectElement, string value)
{
// constants
var script =
"var options = arguments[0].getElementsByTagName('option');" +
"" +
"for(i = 0; i < options.length; i++) {" +
$" if(options[i].getAttribute('value') !== '{value}') {{" +
" continue;" +
" }" +
" options[i].selected = true;" +
" break;" +
"}";
// web element to act on
var onElement = selectElement.WrappedElement;
var onDriver = (IWrapsDriver)onElement;
// execute
((IJavaScriptExecutor)onDriver).ExecuteScript(script, onElement);
}
}
// Usage sample
public class MySeleniumClass
{
public void DoAutomation()
{
var driver = new ChromeDriver()
{
Url = "https://gravitymvctestapplication.azurewebsites.net/UiControls"
};
var element = driver.FindElement(By.Id("select_menu"));
var selectElement = new SelectElement(element);
selectElement.JsSelectByIndex(1);
selectElement.JsSelectByText("Two");
selectElement.JsSelectByValue("3");
}
}
}
Related
I have console log:
info: Microsoft.Hosting.Lifetime[0]
Now listening on: https://localhost:5001
info: Microsoft.Hosting.Lifetime[0]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: E:\github\donhuvy\linkedin_crawler
Staring get info user LinkedIn.
Staring get info user LinkedIn.
1594200496318 mozrunner::runner INFO Running command: "C:\\Program Files\\Firefox Developer Edition\\firefox.exe" "-marionette" "-foreground" "-no-remote" "-profile" "C:\\Users\\MinhPhuc\\AppData\\Local\\Temp\\rust_mozprofileI0zaWu"
1594200496318 mozrunner::runner INFO Running command: "C:\\Program Files\\Firefox Developer Edition\\firefox.exe" "-marionette" "-foreground" "-no-remote" "-profile" "C:\\Users\\MinhPhuc\\AppData\\Local\\Temp\\rust_mozprofile3e8imo"
I have code
using linkedin_mp.Data;
using linkedin_mp.Models;
using Microsoft.AspNetCore.Mvc;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
using SeleniumExtras.WaitHelpers;
using System;
using System.Collections.Generic;
using System.Linq;
namespace linkedin_mp.Controllers
{
// https://localhost:44360/weatherforecast
// https://localhost:5001/linkedin/crawl
// https://localhost:5001/linkedin/profiles
// https://localhost:5001/linkedin/getprofile
[ApiController]
[Route("[controller]")]
public class LinkedInController : ControllerBase
{
public LinkedInController() : base()
{
}
public static void Login()
{
}
[HttpGet]
[Route("crawl")]
public IEnumerable<WordNode> Crawl()
{
List<WordNode> list2 = new List<WordNode>();
// Console.WriteLine("Start crawling.");
// Gọi chương trình bởi API call.
// Lấy danh sách user_id từ database.
// Điền thông tin dữ liệu vào database.
// Điền thông tin version 2 vào database.
// So sánh (diff) dữ liệu 2 version.
// Trả về dữ liệu diff.
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("Staring crawling LinkedIn.");
using IWebDriver driver = new FirefoxDriver();
WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.Navigate().GoToUrl("https://www.linkedin.com/");
driver.FindElement(By.ClassName("nav__button-secondary")).SendKeys(Keys.Return);
// driver.FindElement(By.Id("username")).SendKeys("xx#outlook.com");
// driver.FindElement(By.Id("password")).SendKeys("xx" + Keys.Enter);
// driver.FindElement(By.Id("username")).SendKeys("yyy#gmail.com");
// driver.FindElement(By.Id("password")).SendKeys("yyy" + Keys.Enter);
Entry:
// driver.Navigate().GoToUrl("https://www.linkedin.com/in/loan-duong-567779189/");
string randomLink = getRandomLink();
driver.Navigate().GoToUrl(randomLink);
// Lấy tên user.
// IWebElement webElement = webDriverWait.Until(ExpectedConditions.ElementExists(By.XPath("/html/body/div[8]/div[3]/div/div/div/div/div[2]/main/div[1]/section/div[2]/div[2]/div[1]/ul[1]/li[1]")));
// Console.WriteLine(webElement.GetAttribute("innerHTML").Trim());
// Get linked connection blocks.
// https://stackoverflow.com/a/43489638/3728901
// IEnumerable<IWebElement> connectionBlocks = driver.FindElements(By.XPath("//a[#data-control-name=browsemap_profile]"));
// https://stackoverflow.com/a/12399982/3728901
IEnumerable<IWebElement> connectionBlocks = driver.FindElements(By.XPath("//a[#id[starts-with(., 'ember') and string-length() > 5]]"));
int connectionBlocksTotal = connectionBlocks.ToList().Count;
Console.WriteLine("1. Có từng này block được tìm thấy: " + connectionBlocksTotal);
for (int i = 0; i < connectionBlocksTotal; i++)
{
Console.WriteLine(">> " + i + ". Parsing per block.");
string link = (connectionBlocks.ToList())[i].GetAttribute("href").Trim();
// If link string is LinkiedIn profile URL.
if (isLinkedInProfileURL(link))
{
Profile p2 = new Profile
{
Version = 1,
LinkedinUrl = link,
Created = DateTime.Now,
Modified = DateTime.Now
};
ApplicationDbContext dbContext2 = new ApplicationDbContext();
var profile = from p in dbContext2.Profile
where p.LinkedinUrl == link
select p;
if (profile.FirstOrDefault() == null)
{
dbContext2.Add(p2);
dbContext2.SaveChangesAsync();
Console.WriteLine("Thứ tự >>" + i + "Save " + link + " to database success.");
}
}
}
goto Entry;
// driver.FindElement(By.Name("q")).SendKeys("cheese" + Keys.Enter);
// IWebElement firstResult = wait.Until(ExpectedConditions.ElementExists(By.CssSelector("h3>div")));
//Console.WriteLine(firstResult.GetAttribute("textContent"));
//Profile p1 = new Profile
//{
// Version = 1,
// LinkedinUrl = "https://www.linkedin.com/in/vy-donhu-9a46a91b1x/"
//};
//ApplicationDbContext2 dbContext = new ApplicationDbContext2();
//dbContext.Add(p1);
//dbContext.SaveChangesAsync();
// Console.WriteLine("4. End of program.");
///////////////////////////////////////////
return list2;
}
// https://github.com/lorey/social-media-profiles-regexs#linkedin
/// <summary>
/// Check an URL is LinkedIn profile URL. For example: https://www.linkedin.com/in/stephy-le-793399195/
/// is valid.
/// </summary>
/// <param name="linkedInProfileURL"></param>
/// <returns></returns>
public bool isLinkedInProfileURL(string linkedInProfileURL)
{
string[] prefixes = { "https://www.linkedin.com/in/" };
string[] suffixes = { "/recent-activity/", "/detail/", "/contact-info/" };
// Các kết quả như thế này cần loại bỏ:
// https://www.linkedin.com/in/123linhphuong/detail/recent-activity/
bool resultPrefix = prefixes.Any(prefix => linkedInProfileURL.StartsWith(prefix));
bool resultSuffix = !suffixes.Any(suffix => linkedInProfileURL.EndsWith(suffix));
// string ruleProfile = #"(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/in\/(?P<permalink>[\w\-\_À-ÿ%]+)\/?";
// Regex re = new Regex(ruleProfile);
// return resultPrefix && resultSuffix && re.IsMatch(linkedInProfileURL);
return resultPrefix && resultSuffix;
}
/// <summary>
/// Đếm tổng số bản ghi.
/// </summary>
/// <returns></returns>
public int countNumberOfRecords()
{
ApplicationDbContext applicationDbContext = new ApplicationDbContext();
var profile = from p in applicationDbContext.Profile
select p;
if (profile.FirstOrDefault() == null)
{
return 0;
}
else
{
int totalRecord = profile.ToList().Count();
Console.WriteLine("Tổng số bản ghi: " + totalRecord);
return totalRecord;
}
}
/// <summary>
/// Lấy một liên kết ngẫu nhiên.
/// </summary>
/// <returns></returns>
public string getRandomLink()
{
ApplicationDbContext dbContext2 = new ApplicationDbContext();
var profile = from p in dbContext2.Profile
select p;
Random random = new Random();
int randomNumber = random.Next(0, countNumberOfRecords());
string randomLink = ((Profile)profile.ToList()[randomNumber]).LinkedinUrl;
Console.WriteLine("Link ngẫu nhiên được chọn: " + randomLink);
return randomLink;
}
/// <summary>
/// List all LinkedIn profiles.
/// URL: https://localhost:5001/linkedin/profiles
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("profiles")]
public IEnumerable<string> GetAllProfiles()
{
ApplicationDbContext dbContext = new ApplicationDbContext();
var links = from p in dbContext.Profile
select p.LinkedinUrl;
return links.ToList<string>();
}
/// <summary>
/// Get a specific profile information.
/// URL: https://localhost:5001/linkedin/getprofile
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("getprofile")]
public IEnumerable<string> Get2()
{
List<string> list = new List<string>();
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("Staring get info user LinkedIn.");
// Bat buoc phai load profile dang su dung;
//string PROFILE_DIR = "D://tmp//linkedin_tien";
// FirefoxProfile firefoxProfile = new FirefoxProfile(PROFILE_DIR);
FirefoxProfile firefoxProfile = new FirefoxProfile();
firefoxProfile.SetPreference("permissions.default.image", 2);
firefoxProfile.SetPreference("general.useragent.override", "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25");
FirefoxOptions firefoxOptions = new FirefoxOptions();
//firefoxOptions.Profile = firefoxProfile;
//firefoxOptions.SetPreference("permissions.default.stylesheet", 2);
// firefoxOptions.SetPreference("javascript.enabled", false);
// firefoxOptions.SetPreference("dom.ipc.plugins.enabled.libflashplayer.so", false);
// using IWebDriver driver = new FirefoxDriver(firefoxOptions);
IWebDriver driver = new FirefoxDriver();
WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.Navigate().GoToUrl("https://www.linkedin.com/");
// driver.FindElement(By.Id("username")).SendKeys("xx#outlook.com");
// driver.FindElement(By.Id("password")).SendKeys("xx" + Keys.Enter);
try
{
driver.FindElement(By.ClassName("nav__button-secondary")).SendKeys(Keys.Return);
//driver.FindElement(By.Id("username")).SendKeys("gg#sis.hust.edu.vn");
//driver.FindElement(By.Id("password")).SendKeys("gg" + Keys.Enter);
driver.FindElement(By.Id("username")).SendKeys("xx#outlook.com");
driver.FindElement(By.Id("password")).SendKeys("xx" + Keys.Enter);
}
catch {}
ApplicationDbContext dbContext = new ApplicationDbContext();
var profilesList = from p in dbContext.Profile
//where p.Id >= 425 && p.Id <=528
where p.ProfileName == null
select p;
List<Profile> profiles = profilesList.ToList<Profile>();
List<string> links = new List<string>();
int count = profiles.Count();
//ApplicationDbContext dbContext2 = new ApplicationDbContext();
for (int i = 0; i < profiles.Count(); i++)
// for (int i = 0; i < 3; i++)
{
string url = profiles[i].LinkedinUrl;
driver.Navigate().GoToUrl(url);
Console.WriteLine("url = " + url);
//Profile profile = new Profile();
Profile profile = profiles[i];
// profile.Id = profiles[i].Id;
Console.WriteLine("id = " + profile.Id);
IWebElement webElement1 = webDriverWait.Until(ExpectedConditions.ElementExists(By.CssSelector("li.inline.t-24.t-black.t-normal.break-words")));
string profile_name = webElement1.GetAttribute("innerHTML").Trim();
Console.WriteLine("profile_name = " + profile_name);
profile.ProfileName = profile_name;
// profile_headline
try
{
IWebElement webElement2 = webDriverWait.Until(ExpectedConditions.ElementExists(By.CssSelector("h2.mt1")));
string profile_headline = webElement2.GetAttribute("innerHTML").Trim();
Console.WriteLine("profile_headline = " + profile_headline);
profile.ProfileHeadline = profile_headline;
}
catch
{
}
// short_address
IWebElement webElement3 = webDriverWait.Until(ExpectedConditions.ElementExists(By.CssSelector("li.t-16.t-black.t-normal.inline-block")));
string short_address = webElement3.GetAttribute("innerHTML").Trim();
Console.WriteLine("sort_address = " + short_address);
profile.ProfileAddress = short_address;
profile.Created = DateTime.Now;
profile.Modified = DateTime.Now;
//dbContext2.Profile.Update(profile);
//dbContext2.SaveChangesAsync();
dbContext.Profile.Update(profile);
dbContext.SaveChangesAsync();
Console.WriteLine("Save to table [Profile] success.");
Console.WriteLine("---------------------------------");
// profile_address . đang sai
// IWebElement webElement4 = webDriverWait.Until(ExpectedConditions.ElementExists(By.CssSelector("h2.mt1")));
// Console.WriteLine("profile_address = " + webElement4.GetAttribute("innerHTML").Trim());
// full_address. chưa lấy được từ pop-up.
// IWebElement webElement5 = webDriverWait.Until(ExpectedConditions.ElementExists(By.XPath("//*[#id[starts-with(., 'ember')]/div/section[2]/div/a")));
// Console.WriteLine(webElement5.GetAttribute("innerHTML").Trim());
}
try
{
// temp profile directory path? --> folder watcher;
// Copy temp profile --> PROFILE_DIR --> bypass file: parent.lock
driver.Close();
}
catch { }
return list;
}
}
}
I place debug point at lines
IWebDriver driver = new FirefoxDriver();
WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
I seen 2 instances of Firefox opened.
I want only 1 instance of Firefox, how to do this?
You seem to have two different FF instantiations in your code.
You mention you've put brekpoints on one:
In public IEnumerable<string> Get2() you have: IWebDriver driver = new FirefoxDriver();
But you also have this one:
In public IEnumerable<WordNode> Crawl() you have using IWebDriver driver = new FirefoxDriver();
If you want just one Firefox consolidate it to one instantiation.
Something like creating a property to hold your driver object and instantiate it in the constructor or in a [setup] if your using a unit testing framework. Then remove the other FF instantiations and update all your driver references to this new object.
This depends on how your running your code and if you want parallelization. If you just want a single thread, try something like this:
public class LinkedInController : ControllerBase
{
private IWebDriver driver;
public LinkedInController() : base()
{
//Also do any options stuff here
driver = new FirefoxDriver();
}
//...all your other code
If you've got multiple classes that are using selenium - you should also move the creation and management of your driver object to it's own class. You don't want to start copying and pasting all the driver options into multiple locations.
I have Pengwin (Linux distro optimalized for working with WSL - surely everybody know) with installed github-linguist, set up by tutorial in https://github.com/github/linguist/blob/master/README.md . Even I have use my Insider Windows instance, change version WSL for upcoming 2, but everything keep like before.
In Pengwin and Powershell cmd is everything OK:
wsl bash -c "github-linguist '/mnt/d/Documents/Visual Studio 2017/Projects/LearnCss/LearnCss/Program.cs'"
But by calling in C# is output empty (any other commmand like dir works):
static PowershellBuilder builder = new PowershellBuilder();
/// <summary>
/// Tested, working
/// For every command return at least one entry in result
/// </summary>
/// <param name="commands"></param>
/// <returns></returns>
public async static Task<List< List<string>>> InvokeAsync(IEnumerable<string> commands)
{
List<List<string>> returnList = new List<List<string>>();
PowerShell ps = null;
// After leaving using is closed pipeline, must watch for complete or
using (ps = PowerShell.Create())
{
foreach (var item in commands)
{
ps.AddScript(item);
var async = ps.BeginInvoke();
// Return for SleepWithRandomOutputConsole zero outputs
var psObjects = ps.EndInvoke(async);
returnList.Add(ProcessPSObjects(psObjects));
}
}
return returnList;
}
/// <summary>
/// Tested, working
/// For every command return at least one entry in result
/// </summary>
/// <param name="commands"></param>
/// <returns></returns>
public static List<List<string>> Invoke(IEnumerable<string> commands)
{
var result = InvokeAsync(commands);
result.Wait();
return result.Result;
}
private static List<string> ProcessPSObjects(ICollection<PSObject> pso)
{
List<string> output = new List<string>();
foreach (var item in pso)
{
if (item != null)
{
output.Add(item.ToString());
}
}
return output;
}
public static List<string> InvokeSingle(string command)
{
return Invoke(CA.ToListString(command))[0];
}
But with calling with Process.Start all works like a charm:
/// <summary>
/// If in A1 will be full path specified = 'The system cannot find the file specified'
/// A1 if dont contains extension, append exe
/// </summary>
/// <param name="exeFileNameWithoutPath"></param>
/// <param name="arguments"></param>
/// <returns></returns>
public static List<string> InvokeProcess(string exeFileNameWithoutPath, string arguments)
{
FS.AddExtensionIfDontHave(exeFileNameWithoutPath, AllExtensions.exe);
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
// Must contains only filename, not full path
pProcess.StartInfo.FileName = exeFileNameWithoutPath;
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = arguments;
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;
//Optional, recommended do not enter, then old value is not deleted and both paths is combined
//pProcess.StartInfo.WorkingDirectory = ;
//Start the process
pProcess.Start();
W32.EnableWow64FSRedirection(true);
//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();
//Wait for process to finish
pProcess.WaitForExit();
var result = SH.GetLines(strOutput);
return result;
}
Calling code:
const string lang = "language:";
public static string DetectLanguageForFileGithubLinguist(string windowsPath)
{
string command = null;
string arguments = null;
// With WSL or WSL 2 not working. In both cases Powershell returns right values but in c# everything empty. Asked on StackOverflow
StringBuilder linuxPath = new StringBuilder();
linuxPath.Append("/mnt/");
linuxPath.Append(windowsPath[0].ToString().ToLower());
var parts = SH.Split(windowsPath, AllStrings.bs);
for (int i = 1; i < parts.Count; i++)
{
linuxPath.Append("/" + parts[i]);
}
command = "wsl";
arguments = " bash -c \"github-linguist '" + linuxPath + "'\"";
W32.EnableWow64FSRedirection(false);
// empty
var pc = PowershellRunner.InvokeSingle("cmd /c bash -c 'ruby -v'");
// empty
var pc2 = PowershellRunner.InvokeSingle("wsl bash -c whoami");
// with content
var pc3 = PowershellRunner.InvokeSingle("dir");
//command = #"c:\Windows\System32\wsl.exe";
//arguments = " -- github-linguist \"/mnt/d/Documents/Visual Studio 2017/Projects/LearnCss/LearnCss/Program.cs\"";
// empty
var pc4 = PowershellRunner.InvokeSingle(command + arguments);
PowershellRunner.InvokeProcess(command + ".exe", arguments);
var lines = PowershellRunner.InvokeSingle(command);
var line = CA.ReturnWhichContains(lines, lang).FirstOrNull();
if (line == null)
{
return null;
}
var result = line.ToString().Replace(lang, string.Empty).Trim();
return result;
}
Why calling with PowerShell class is not working?
i am using .netcore with Microsoft.Extensions.Caching.Distributed , i have a scenario to get all the keys and also i need to flush all the values.
I have searched many articles no one gives the exact idea to get all values or Flush values. IDistributedCache don't have flush the redis cache.
Can anyone help on this.
For my project ,the follow function return all matched keys:
//using StackExchange.Redis;
/// <summary>
/// 搜索所有与<see cref="keyStr"/>相匹配的缓存的key
/// </summary>
/// <param name="keyStr">搜索词,*表示任意字符</param>
/// <param name="dbIndex">redis中查找db</param>
/// <param name="trimRedisInstanceName">是否在查询前及返回前去除<see cref="Extension.RedisInstanceName"/>前缀</param>
/// <returns>redis中的key列表,<see cref="trimRedisInstanceName"/>参数设置是否包括<see cref="Extension.RedisInstanceName"/></returns>
protected async Task<List<string>> FilterByKey(string keyStr, int dbIndex = 0, bool trimRedisInstanceName = true)
{
//创建连接
var conn = await ConnectionMultiplexer.ConnectAsync(_configuration.GetSection("Cache")["Redis"]);
//获取db
var db = conn.GetDatabase(dbIndex);
var listResult = new List<string>();
//遍历集群内服务器
foreach (var endPoint in conn.GetEndPoints())
{
//获取指定服务器
var server = conn.GetServer(endPoint);
//在指定服务器上使用 keys 或者 scan 命令来遍历key
foreach (var key in server.Keys(dbIndex, Extension.RedisInstanceName + keyStr))
{
if (trimRedisInstanceName)
{
listResult.Add(key.ToString().Replace(Extension.RedisInstanceName, ""));
}
else
{
listResult.Add(key);
}
//获取key对于的值
//var val = db.StringGet(key);
Console.WriteLine($"key: {key}, value:");
}
}
return listResult;
}
In the method,Extension.RedisInstanceName used in
services.AddStackExchangeRedisCache(options =>
{
options.Configuration = config.GetSection("Cache")["Redis"];
options.InstanceName = RedisInstanceName;
});
it used by this:
//刷新缓存
var allCacheCompany = await FilterByKey("xxxx.*");
foreach (var companyKey in allCacheCompany)
{
await _cache.RemoveAsync(companyKey);
}
I am currently trying to generate a CSV using nhibernate. This error does not occur on my development enviroment but it does on the live site that it's being used on. I have tried fiddling with time out's but this does not seem to have any effect as it's timing out way before it should. The timing is completely random, sometimes it'll be 3 seconds before it times out the next it will be 10 seconds. There doesn't seem to be any real consistancy in the timing.
Stack Trace:
System.Web.HttpException: The remote host closed the connection. The error code is 0x800703E3.
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at Reports.CustomCSVWriter.WritetoHttpStream(String filename, Boolean header)
The code is as follows:
public class ProductSpreadSheetDownload : CustomCSVWriter
{
protected override string[] GetCollection()
{
Page.Server.ScriptTimeout = 300;
IList<Product> products = new List<Product>();
IStockScheme stockScheme = Fabric.ObjectProvider.Get<IStockScheme>();
ICriteria criteria = CoreHttpModule.Session.CreateCriteria(typeof(Product))
.Add(NHibernate.Expression.Expression.IsNotNull(Product.STOCK_CODE))
.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true))
.Add(NHibernate.Expression.Expression.Eq(Product.STOCK_TYPE, StockType.StockItem))
.Add(NHibernate.Expression.Expression.Not(NHibernate.Expression.Expression.Like(Product.NAME, "%*%")));
AddCustomCriteria(criteria);
products = criteria.List<Product>();
products = Product.RemoveOrphanedAndUnrooted((List<Product>)products);
Product[] productArray = new Product[products.Count];
products.CopyTo(productArray, 0);
double?[] levels = stockScheme.GetStock(productArray, false);
List<string> productStringList = new List<string>();
IProductMapper mapper = Fabric.ObjectProvider.Get<IProductMapper>();
var rootUrl = Fabric.SettingsProvider.ReadSetting<string>("RootUrl", string.Empty);
string showOutOfStock = Page.Request.QueryString["ShowOutOfStock"];
int minStockLevel = int.MinValue;
if (showOutOfStock == "False")
minStockLevel = 0;
for (int i = 0; i < productArray.Length; i++)
{
if (levels[i] > minStockLevel && levels[i] != null && productArray[i].Parent != null && productArray[i].Parent.IsVisibleOnWebsite)
{
StringBuilder productStringBuilder = new StringBuilder();
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Name));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].StockCode));
productStringBuilder.AppendFormat("{0}, ", levels[i]);
productStringBuilder.AppendFormat("{0}, ", mapper.GetUrl(productArray[i]) );
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].Category));
productStringBuilder.AppendFormat("{0}, ", CleanString(productArray[i].SubCategory));
productStringBuilder.AppendFormat("{0}, ", CleanString(mapper.GetText(productArray[i], "Description")));
productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
AddCustomFields(productStringBuilder, mapper);
productStringList.Add(productStringBuilder.ToString().Trim().TrimEnd(','));
}
}
string[] productstrings = new string[productStringList.Count];
productStringList.CopyTo(productstrings, 0);
return productstrings;
}
/// <summary>
/// Override this method to add custom criteria to the feed
/// </summary>
/// <example>
/// criteria.Add(NHibernate.Expression.Expression.Eq(Product.IS_VISIBLE_ON_WEBSITE, true));
/// </example>
protected virtual void AddCustomCriteria(ICriteria criteria) {}
/// <summary>
/// Override this method to add custom fields to the CSV output
/// </summary>
/// <example>
/// productStringBuilder.AppendFormat("{0}, ", mapper.GetImageUrl(productArray[i], "Main"));
/// </example>
protected virtual void AddCustomFields(StringBuilder productStringBuilder, IProductMapper mapper) { }
protected override string Headers()
{
string headers = "Name, Stockcode, Stock_Level, URL, Category, SubCategory, Description, Main Image URL";
return headers;
}
/// <summary>
/// Removes characters that are not safe in a CSV file.
/// </summary>
protected static string CleanString(string stringToClean)
{
return string.IsNullOrEmpty(stringToClean) ? string.Empty : stringToClean.Replace("\n", " ").Replace(',', ' ');
}
}
}
I am creating an email software which send email to some accounts. I want to append text every time new email is sent or failed. But textbox shows me report after sending all emails. If the toList is very large like 30+ emails the app screen goes white and after sending all emails GUI comes back with the updated OutPutTextBox. Here is the code inside the SendButton_Click method
foreach (String to in toList)
{
bool hasSent = SendMail(from, "password", to, SubjectTextBox.Text, BodyTextBox.Text);
if (hasSent)
{
OutPutTextBox.appendText("Sent to: " + to);
}
else
{
OutPutTextBox.appendText("Failed to: " + to);
}
}
What you actually want to do is invoke SendMail asynchronously. There are several ways to do this in .NET 4.0. I recommend starting a Task object in your foreach loop, and scheduling a task continuation for each one to the UI thread:
string subject = SubjectTextBox.Text;
string body = BodyTextBox.Text;
var ui = TaskScheduler.FromCurrentSynchronizationContext();
List<Task> mails = new List<Task>();
foreach (string to in toList)
{
string target = to;
var t = Task.Factory.StartNew(() => SendMail(from, "password", target, subject, body))
.ContinueWith(task =>
{
if (task.Result)
{
OutPutTextBox.appendText("Sent to: " + to);
}
else
{
OutPutTextBox.appendText("Failed to: " + to);
}
}, ui);
mails.Add(t);
}
Task.ContinueWhenAll(mails.ToArray(), _ => { /* do something */ });
(syntax might be slightly off; I didn't compile it).
This seems to work (assumes a WinForm application):
namespace WindowsFormsApplication5
{
using System;
using System.Threading;
using System.Windows.Forms;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
TextBox OutPutTextBox = new TextBox();
/// <summary>
/// Represents Send Mail information.
/// </summary>
class MailInfo
{
public string from;
public string password;
public string to;
public string subject;
public string body;
}
void ProcessToDoList( string[] toList )
{
foreach ( var to in toList )
{
MailInfo info = new MailInfo();
info.from = "xx"; //TODO.
info.password = "yy"; //TODO.
info.to = "zz"; //TODO.
info.subject = "aa"; //TODO.
info.body = "bb"; //TODO.
ThreadPool.QueueUserWorkItem( this.SendMail, info );
}
}
/// <summary>
/// Send mail.
/// NOTE: this occurs on a separate, non-UI thread.
/// </summary>
/// <param name="o">Send mail information.</param>
void SendMail( object o )
{
MailInfo info = ( MailInfo )o;
bool hasSent = false;
//TODO: put your SendMail implementation here. Set hasSent field.
//
// Now test result and append text.
//
if ( hasSent )
{
this.AppendText( "Sent to: " + info.to );
}
else
{
this.AppendText( "Failed to: " + info.to );
}
}
/// <summary>
/// Appends the specified text to the TextBox control.
/// NOTE: this can be called from any thread.
/// </summary>
/// <param name="text">The text to append.</param>
void AppendText( string text )
{
if ( this.InvokeRequired )
{
this.BeginInvoke( ( Action )delegate { this.AppendText( text ); } );
return;
}
OutPutTextBox.AppendText( text );
}
}
}