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.
Related
I am new to automation, I just learned about Selenium for 3 days and built a simple C# console application with Selenium which trying to automate "sell" request on a trading website.
I noticed when I login the trading website with normal Chrome, the site is working as normal. But when I launch it with my C# console app, it seems like the trading website is not functioning as normal, seems dead.
Here I attached with both developer console picture as reference.
Normal Chrome browser:
enter image description here
Launched with C# console app:
enter image description here
Am I missing any part of my code, and cause the launched Chrome is being "locked".
Please help me
below is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using WebDriverManager;
using WebDriverManager.DriverConfigs.Impl;
namespace ii.tfxBot
{
class Program
{
static void Main(string[] args)
{
string ExecuteUrl = "https://tex.tfxi.com/#/exchange/tfx_usdt";
Console.WriteLine("test case started ");
//create the reference for the browser
//new DriverManager().SetUpDriver(new ChromeConfig());
var ccOptions = new ChromeOptions();
ccOptions.LeaveBrowserRunning = true;
//ccOptions.AttachToEdgeChrome = true;
//change the path accordingly
//ccOptions.EdgeExecutablePath = "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe";
new DriverManager().SetUpDriver(new ChromeConfig());
var driver = new ChromeDriver(#"C:\WebDriver\bin", ccOptions);
// navigate to URL
driver.Navigate().GoToUrl("https://tex.tfxi.com/#/login");
Thread.Sleep(2000);
// identify the Google search text box
//IWebElement ele = driver.FindElement(By.Name("q"));
////enter the value in the google search text box
//ele.SendKeys("javatpoint tutorials");
//Thread.Sleep(2000);
////identify the google search button
//IWebElement ele1 = driver.FindElement(By.Name("btnK"));
//// click on the Google search button
//ele1.Click();
bool isUrl = false;
while (isUrl == false)
{
if (driver.Url == ExecuteUrl)
{
StartExecution(driver);
break;
}
Console.WriteLine("Execute Url not matched... try again in 1 second");
Thread.Sleep(5000);
}
//close the browser
//driver.Close();
Thread.Sleep(8000000);
Console.WriteLine("test case ended ");
}
private static void StartExecution(ChromeDriver driver)
{
var inputElements = driver.FindElements(By.CssSelector(".ivu-input.ivu-input-default"));
int i = 0;
foreach (var inputElement in inputElements)
{
Console.WriteLine("input count " + i.ToString() + " : " + inputElement.GetAttribute("placeholder").ToString());
string plText = inputElement.GetAttribute("placeholder").ToString();
if (plText == "出售數量")
{
Console.WriteLine("found the input number: " + i.ToString());
}
else
{
//inputElement.SendKeys("28000");
}
i++;
}
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(300));
IWebElement divLimit;
bool found = false;
while (found == false)
{
//divLimit = driver.FindElement(By.ClassName("bd bd_limited"));
//divLimit = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(By.CssSelector("bd bd_limited")));
divLimit = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(By.CssSelector(".bd.bd_limited"))); ;
if (divLimit != null)
{
Console.WriteLine("item found, proceed to get selling price!");
GetSellingPrice(divLimit);
break;
}
Console.WriteLine("item NOT found!");
Thread.Sleep(300);
}
int tfxBal = GetTfxBalance(driver);
WaitforElement(driver, By.CssSelector(".mask2"), tfxBal);
}
public static int GetTfxBalance(ChromeDriver driver)
{
int TfxBal = 0;
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(300));
IWebElement divHdLogin;
divHdLogin = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(By.CssSelector(".hd.hd_login")));
//(IWebElement)driver.FindElements(By.CssSelector(".hd.hd_login"));
var targetKeys = divHdLogin.FindElements(By.TagName("span"));
Console.WriteLine("targetKeys 0 : " + targetKeys[0].Text);
Console.WriteLine("targetKeys 1 : " + targetKeys[1].Text);
Console.WriteLine("targetKeys 2 : " + targetKeys[2].Text);
decimal o = Convert.ToDecimal(targetKeys[1].Text);
if (targetKeys[1].Text.Contains("."))
{
var a = targetKeys[1].Text.Split('.');
TfxBal = Convert.ToInt32(a[0]);
}
else
{
TfxBal = Convert.ToInt32(targetKeys[1].Text);
}
return TfxBal;
}
public static void GetSellingPrice(IWebElement divLimit)
{
IWebElement divFormContent = divLimit.FindElement(By.CssSelector(".ivu-form-item-content"));
IWebElement ipSellPrice = divFormContent.FindElement(By.CssSelector(".ivu-input.ivu-input-default"));
Console.WriteLine(ipSellPrice.GetAttribute("value"));
}
public static bool Elexists(By by, WebDriver driver)
{
try
{
driver.FindElement(by);
IWebElement divPopup = driver.FindElement(by);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromMilliseconds(300));
// textLeft countNumber
IWebElement divcountNumber;
divcountNumber = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementExists(By.CssSelector(".textLeft.countNumber")));
//Console.WriteLine("count number: " + divcountNumber.Text);
string popupStyle = divPopup.GetAttribute("style");
//Console.WriteLine("div Popup Style : " + popupStyle);
if (popupStyle == "display: none;")
{
//Console.WriteLine("No Pop up..");
return false;
}
else
{
Console.WriteLine("Pop up display has changed!");
return true;
}
}
catch (NoSuchElementException)
{
return false;
}
}
public static void WaitforElement(WebDriver driver, By by, int tfxBalance = 0)
{
// waitforMin = 2 hours
int waitforMin = 60 * 1000 * 2 * 2 * 2;
for (int i = 0; i < waitforMin; i++)
{
System.Threading.Thread.Sleep(250);
if (Elexists(by, driver))
{
Console.WriteLine("Pop up appears! Performing selling now");
var inputElements = driver.FindElements(By.CssSelector(".ivu-input.ivu-input-default"));
IWebElement SellBtn = driver.FindElement(By.CssSelector(".bg-red.ivu-btn.ivu-btn-default.ivu-btn-long"));
foreach (var inputElement in inputElements)
{
string plText = inputElement.GetAttribute("placeholder").ToString();
if (plText == "出售數量")
{
Console.WriteLine("found the input box");
inputElement.SendKeys("28000");
SellBtn.Click();
}
}
break;
}
Console.Write(".");
}
}
public static void SellTfx()
{
//
}
}
}
I am expecting some solution to fix my code
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");
}
}
}
I am looking to loop through all SAP GuiComponents in c# but am struggling to get all the children of children of a gui session.
This is what I have so far (initially passing session.ActiveWindow.Children to nodes):
private void IterateFindIDByNAme(GuiComponentCollection nodes, string searchstring)
{
if (foundID == "")
{
foreach (GuiComponent node in (GuiComponentCollection)nodes)
{
var comp = node;
if (comp.Name.Contains(searchstring))
foundID = comp.Id;
else
{
try
{
FindIDByNAme((GuiComponentCollection)node, searchstring);
}
catch { }
}
}
}
}
Its able to get all the child elements of session.ActiveWindow but when trying to cast all the children to GuiComponentCollections its falling over.
This would be irrelevant if I could use the FindByName function but for some reason it is not working on the SAP screen i am currently working on (it does work on others, not sure why).
The ID of the field is:
wnd[0]/usr/subBCA_SUB_HEADER:SAPLBANK_BDT_CTRL:0100/subSUBS_DETAIL:SAPLBUSS:0028/ssubGENSUB:SAPLBUSS:4038/subA01P02:SAPLBCA_DYN_CN_CNMANO:0002/ctxtBCA_DYN_CONTRACT_ORGENTRY-ORGUNIT
and the function I am trying is:
((GuiTextField)session.FindByName("BCA_DYN_CONTRACT_ORGENTRY-ORGUNIT", "GuiTextField")).Text = "Test";
The findbyid works fine, but not findbyname?
I know this is 2 questions, but kind of related.
ctxtBCA_DYN_CONTRACT_ORGENTRY-ORGUNIT
The type of the control is a GuiCTextField not GuiTextField:
session.FindByName("BCA_DYN_CONTRACT_ORGENTRY-ORGUNIT", "GuiCTextField")
Sample Code :
public DateTime? GetModificationDate(int employeeID)
{
var session = SapHelper.GetActiveSession();
Console.WriteLine("Recherche de la measure [A5 ou A6] avec un motif 90...");
var window = session.BeginTransaction("PA20", "Afficher données de base personnel");
window.FindByName<GuiCTextField>("RP50G-PERNR").Text = employeeID.ToString();
window.FindByName<GuiCTextField>("RP50G-CHOIC").Text = "Mesures (0000)";
window.FindByName<GuiCTextField>("RP50G-SUBTY").Text = null;
window.FindByName<GuiButton>("btn[20]").Press(); // list view
if (window.Text == "Afficher données de base personnel")
{
Console.WriteLine(">> " + window.FindByName<GuiStatusbar>("sbar").Text);
return null;
}
/* Index Type Title Tooltip
0 GuiTextField Début Date de début
1 GuiTextField Fin Date de fin
2 GuiCTextField Mes. Catégorie de mesure
3 GuiTextField Dés. cat. mesure Dés. cat. mesure
4 GuiCTextField MotMe Motif mesure
5 GuiTextField Dés. motif mesure Dés. motif mesure
6 GuiCTextField Client Statut propre client
7 GuiCTextField Activité Statut d'activité
8 GuiCTextField Paiement Statut paiement part */
var result = window.FindByName<GuiTableControl>("MP000000TC3000").AsEnumerable()
.Select(x => new
{
Start = x.GetText(0),
Category = x.GetCText(2),
CategoryText = x.GetText(3),
Reason = x.GetCText(4),
ReasonText = x.GetText(5),
})
.Where(x => (x.Category == "A5" || x.Category == "AG") && x.Reason == "90")
.FirstOrDefault();
if (result == null)
{
Console.WriteLine(">> aucune measure [A5 ou A6] avec un motif 90 trouvée");
return null;
}
else
{
Console.WriteLine(">> {0}:[{1}]{2} [{3}]{4}",
result.Start, result.Category, result.Category, result.Reason, result.ReasonText);
return DateTime.ParseExact(result.Start, "yyyy/MM/dd", CultureInfo.InvariantCulture);
}
}
Xy.Sap :
#region namespace Xy.Sap
namespace Xy.Sap
{
using System.Reflection;
using sapfewse;
using saprotwr.net;
using COMException = System.Runtime.InteropServices.COMException;
public static class SapHelper
{
public static GuiSession GetActiveSession()
{
var rot = new CSapROTWrapper().GetROTEntry("SAPGUI");
if (rot == null)
throw SapException.NotOpened();
var app = (GuiApplication)rot.GetType().InvokeMember("GetScriptingEngine", BindingFlags.InvokeMethod, null, rot, null);
var connectedSession = app.Connections.Cast<GuiConnection>()
.SelectMany(x => x.Children.Cast<GuiSession>())
.Where(x => !string.IsNullOrEmpty(x.Info.User))
.FirstOrDefault();
if (connectedSession == null)
throw SapException.NotOpened();
return connectedSession;
}
}
public class SapException : Exception
{
public SapException(string message) : base(message) { }
public static SapException NotOpened()
{
return new SapException("Veuillez lancer le SAP et de connecter avec votre identité");
}
}
public static class SapExtensions
{
#region GuiSession
/// <summary>
/// Shortcut for PA20 query
/// </summary>
/// <param name="session"></param>
/// <param name="employeeID"></param>
/// <param name="it">Infotype ID</param>
/// <param name="sty">Subtype ID</param>
/// <param name="asListView"></param>
/// <returns></returns>
public static GuiFrameWindow QueryPA20(this GuiSession session, int employeeID, string it, string sty = null, bool asListView = false)
{
var window = session.BeginTransaction("PA20", "Afficher données de base personnel");
window.FindByName<GuiCTextField>("RP50G-PERNR").Text = employeeID.ToString();
window.FindByName<GuiCTextField>("RP50G-CHOIC").Text = it;
window.FindByName<GuiCTextField>("RP50G-SUBTY").Text = sty;
window.FindByName<GuiButton>(asListView ? "btn[20]" : "btn[7]").Press();
if (window.Text == "Afficher données de base personnel")
{
var exception = new InvalidOperationException(string.Format("Failed to access to personal information of {0}", employeeID));
exception.Data["Employee ID"] = employeeID;
exception.Data["Infotype"] = it;
exception.Data["Subtype"] = sty;
exception.Data["View"] = asListView ? "ListView[Mont]" : "RecordView[Glasses]";
exception.Data["Status Message"] = window.FindByName<GuiStatusbar>("sbar").Text;
throw exception;
}
return window;
}
/// <summary>
/// Shortcut for PA30 query
/// </summary>
/// <param name="session"></param>
/// <param name="employeeID"></param>
/// <param name="it">Infotype ID</param>
/// <param name="sty">Subtype ID</param>
/// <param name="asListView"></param>
/// <returns></returns>
public static GuiFrameWindow QueryPA30(this GuiSession session, int employeeID, string it, string sty = null)
{
var window = session.BeginTransaction("PA30", "Gérer données de base HR");
window.FindByName<GuiCTextField>("RP50G-PERNR").Text = employeeID.ToString();
window.FindByName<GuiCTextField>("RP50G-CHOIC").Text = it;
window.FindByName<GuiCTextField>("RP50G-SUBTY").Text = sty;
window.FindByName<GuiButton>("btn[6]").Press();
if (window.Text == "Gérer données de base HR")
{
var exception = new InvalidOperationException(string.Format("Failed to access to personal information of {0}", employeeID));
exception.Data["Employee ID"] = employeeID;
exception.Data["Infotype"] = it;
exception.Data["Subtype"] = sty;
exception.Data["Status Message"] = window.FindByName<GuiStatusbar>("sbar").Text;
throw exception;
}
return window;
}
/// <summary>
/// Start a new transaction and return the active window
/// </summary>
public static GuiFrameWindow BeginTransaction(this GuiSession session, string transactionID, string expectedTitle)
{
return session.BeginTransaction(transactionID,
x => x.Text == expectedTitle,
x =>
{
var exception = new InvalidOperationException(string.Format("Failed to open transaction : {0}", transactionID));
exception.Data["Transaction ID"] = transactionID;
exception.Data["Expected Title"] = expectedTitle;
exception.Data["Current Title"] = x.Text;
exception.Data["Status Message"] = x.FindByName<GuiStatusbar>("sbar").Text;
return exception;
});
}
public static GuiFrameWindow BeginTransaction(this GuiSession session, string transactionID, Predicate<GuiFrameWindow> validation, Func<GuiFrameWindow, string> errorFormatter)
{
return session.BeginTransactionImpl(transactionID, validation, x => new Exception(errorFormatter(x)));
}
public static GuiFrameWindow BeginTransaction(this GuiSession session, string transactionID, Predicate<GuiFrameWindow> validation, Func<GuiFrameWindow, Exception> errorBuilder)
{
return session.BeginTransactionImpl(transactionID, validation, errorBuilder);
}
private static GuiFrameWindow BeginTransactionImpl(this GuiSession session, string transactionID, Predicate<GuiFrameWindow> validation, Func<GuiFrameWindow, Exception> errorBuilder)
{
// force current transaction to end, preventing any blocking(eg: model dialog)
session.EndTransaction();
session.StartTransaction(transactionID);
var window = session.ActiveWindow;
if (!validation(window))
throw errorBuilder(window);
return window;
}
#endregion
#region GuiFrameWindow
public static TSapControl FindByName<TSapControl>(this GuiFrameWindow window, string name)
{
try
{
return (TSapControl)window.FindByName(name, typeof(TSapControl).Name);
}
catch (COMException e)
{
var writer = new StringWriter();
writer.WriteLine("The control could not be found by name and type.");
writer.WriteLine("Name : " + name);
writer.WriteLine("Type : " + typeof(TSapControl).Name);
throw new Exception(writer.ToString(), e);
}
}
#endregion
#region GuiTableControl
/// <summary>Note: Do not iterate through this ienumerable more than once</summary>
public static IEnumerable<GuiTableRow> AsEnumerable(this GuiTableControl table)
{
var container = table.Parent as dynamic;
string name = table.Name, type = table.Type;
int rowCount = table.VerticalScrollbar.Maximum;
Func<GuiTableControl> getTable = () => container.FindByName(name, type) as GuiTableControl;
for (int i = 0; i <= rowCount; i++)
{
getTable().VerticalScrollbar.Position = i;
yield return getTable().Rows.Item(0) as GuiTableRow;
}
}
public static TSapControl GetCell<TSapControl>(this GuiTableRow row, int column)
{
return (TSapControl)row.Item(column);
}
public static string GetCText(this GuiTableRow row, int column)
{
return row.GetCell<GuiCTextField>(column).Text;
}
public static string GetText(this GuiTableRow row, int column)
{
return row.GetCell<GuiTextField>(column).Text;
}
#endregion
}
}
#endregion
EDIT: The link to the LINQPad script mentioned in comment below no longer works. I have re-uploaded it here.
This script helps you to browse SAP GUI:
List control type, name, id, content
List properties and methods
Highlight control
Generate selector : .FindByName<GuiTableControl>("MP000000TC3000")
In case anyone wants to know how to get child elements of any gui component (this will simply write all ids to the console):
private void LoopAllElements(GuiComponentCollection nodes)
{
foreach (GuiComponent node in (GuiComponentCollection)nodes)
{
Console.WriteLine(node.Id);
if (node.ContainerType)
{
var children = ((node as dynamic).Children as GuiComponentCollection);
LoopAllElements(children);
}
}
}
This will loop through all child elements of any GUIComponentCollection you pass to it such as
LoopAllElements(session.Children)
There is probably a better linq way of doing this but this should get you started.
Please also check out this gist created by Xiaoy312 https://gist.github.com/Xiaoy312/a1424bd34acae92554105b27b0c80971
this has a lot of useful functions to debug your current sap session which i have found extremely useful.
You can either view the code as it has a number of functions you can use such as improved findbyid and findbyname or run it in linqpad https://www.linqpad.net/Download.aspx which will allow you to interogate the current SAP session.
If I understood correctly we have to manually start SAP Logon to make line below working:
var rot = new CSapROTWrapper().GetROTEntry("SAPGUI");
Am I right?
If so maybe someone can explain me why at the line:
var app = (GuiApplication)rot.GetType().InvokeMember("GetScriptingEngine", BindingFlags.InvokeMethod, null, rot, null);
I am getting exception:
An exception of type 'System.Runtime.InteropServices.COMException'
occurred in System.Dynamic.dll but was not handled in user code
Additional information: Error loading type library/DLL. (Exception
from HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))
I've already tried to change target platform from Any CPU to x86 and x64 and didn't have success in resolving this problem.
But when I run SAPGUI using following script:
var SapGuiApp = new GuiApplication();
string development = "Development ERP System";
var connection = SapGuiApp.OpenConnection(development);
instead of running SAP Logon manually described above problem is not reproducing.
But in this case I have other problem: GUI is different and for second option GUI looks corrupted - some of GUI controls are not displayed (please see screenshot). Please give me advice what can be wrong? Thank you in advance
UPDATE: I found solution that solves issue described below. You have to use object instead of var while you are trying to get session connection:
CSapROTWrapper sapROTWrapper = new CSapROTWrapper();
object rot = sapROTWrapper.GetROTEntry("SAPGUI");
object engine = rot.GetType().InvokeMember("GetScriptingEngine", System.Reflection.BindingFlags.InvokeMethod, null, rot, null);
GuiConnection connection = (engine as GuiApplication).OpenConnection(connectionName);
GuiSession session = connection.Children.ElementAt(0) as GuiSession;
Here's what's going on. I have an ASP.NET MVC 4 Web API web application. I can call API resources via URL. One of these functions get performance monitoring data for a specified amount of time and returns it in JSON once it has completed. However, what I want to do is return
It is IMPORTANT to note that I am working with a the browser and API resources in the model, not with a View. Please don't casually tell me to use Javascript in a View, because there is no view, or tell me to look at the SignalR wiki because the information for ".NET" sections is meant for desktop applications, not web apps. For example, you can't "Console.WriteLine()" to a browser.
To reiterate, I am using ASP.NET MVC 4 Web API to develop an API, and am calling the API via URL in the browser and it is returning JSON. I am attempting to use SignalR to have the app send JSON to the browser, but it is not doing anything at all. Rather, the application simply returns the completed JSON from the controller action with all of the performance data values once the process has completed. In other words, SignalR is not working.
So what I'm trying to do is while the API resource is gathering all the information, SignalR sends JSON to the browser every second so that the client can see what's going on in real time.
What I need to find out is why SignalR isn't sending it, and how I can send information to be displayed in the browser without Javascript, since I'm working from a model class, not from a view.
As you can see, I subscribe to the event using On, and then use Invoke to call the server-side hub method SendToClient.
Please let me know if I'm trying to do is impossible. I have never heard of a "real-time", dynamic API call via URL.
Here is my hub class. It is located in ~/signalr/hubs and is in a file called LiveHub.cs. The method Send is what I am trying to invoke in the method seen in the next code block.
namespace PerfMon2.signalr.hubs
{
public class LiveHub : Hub
{
public void SendToClient(List<DataValueInfo> json)
{
Clients.showValue(json);
}
}
}
Here is the method from LogDBRepository.cs that includes the SignalR calls.
public List<LogInfo> LogTimedPerfData(string macName, string categoryName, string counterName,
string instanceName, string logName, string live, long? seconds)
{
iModsDBRepository modsDB = new iModsDBRepository();
List<MachineInfo> theMac = modsDB.GetMachineByName(macName);
if (theMac.Count == 0)
return new List<LogInfo>();
else if (instanceName == null)
{
if (!PerformanceCounterCategory.Exists(categoryName, macName) ||
!PerformanceCounterCategory.CounterExists(counterName, categoryName, macName) )
{
return new List<LogInfo>();
}
}
else if (instanceName != null)
{
if (!PerformanceCounterCategory.Exists(categoryName, macName) ||
!PerformanceCounterCategory.CounterExists(counterName, categoryName, macName) ||
!PerformanceCounterCategory.InstanceExists(instanceName, categoryName, macName))
{
return new List<LogInfo>();
}
}
else if (logName == null)
{
return new List<LogInfo>();
}
// Check if entered log name is a duplicate for the authenticated user
List<LogInfo> checkDuplicateLog = this.GetSingleLog(logName);
if (checkDuplicateLog.Count > 0)
{
return new List<LogInfo>();
}
PerformanceCounterCategory category = new PerformanceCounterCategory(categoryName, theMac[0].MachineName);
if (category.CategoryName == null || category.MachineName == null)
{
return new List<LogInfo>();
}
List<LogInfo> logIt = new List<LogInfo>();
if (category.CategoryType != PerformanceCounterCategoryType.SingleInstance)
{
List<InstanceInfo> instances = modsDB.GetInstancesFromCatMacName(theMac[0].MachineName, category.CategoryName);
foreach (InstanceInfo inst in instances)
{
if (!category.InstanceExists(inst.InstanceName))
{
continue;
}
else if (inst.InstanceName.Equals(instanceName, StringComparison.OrdinalIgnoreCase))
{
PerformanceCounter perfCounter = new PerformanceCounter(categoryName, counterName,
inst.InstanceName, theMac[0].MachineName);
//CounterSample data = perfCounter.NextSample();
//double value = CounterSample.Calculate(data, perfCounter.NextSample());
string data = "";
List<UserInfo> currUser = this.GetUserByName(WindowsIdentity.GetCurrent().Name);
string timeStarted = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
//string[] dataValues = new string[(int)seconds];
List<string> dataValues = new List<string>();
var hubConnection = new HubConnection("http://localhost/PerfMon2/");
hubConnection.Credentials = CredentialCache.DefaultNetworkCredentials;
var perfMon = hubConnection.CreateProxy("LiveHub");
// perfMon.On("sendValue", message => Console.WriteLine(message));
perfMon.On("showValue", json => Console.WriteLine(json));
hubConnection.Start().Wait();
List<DataValueInfo> lol = new List<DataValueInfo>();
for (int i = 0; i < seconds; i++)
{
data = "Value " + i + ": " + perfCounter.NextValue().ToString();
//dataValues[i] = data;
dataValues.Add(data);
lol.Add(new DataValueInfo
{
Value = perfCounter.NextValue().ToString()
});
// perfMon.Invoke<List<DataValueInfo>>("Send", lol);
perfMon.Invoke("SendToClient", lol);
Thread.Sleep(1000);
}
string timeFinished = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
Log log = new Log
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = string.Join(",", dataValues),
UserID = currUser[0].UserID
};
this.CreateLog(log);
logIt.Add(new LogInfo
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = dataValues.ToList<string>()
});
break;
}
}
}
else
{
PerformanceCounter perfCounter = new PerformanceCounter(categoryName, counterName,
"", theMac[0].MachineName);
string data = "";
List<UserInfo> currUser = this.GetUserByName(WindowsIdentity.GetCurrent().Name);
string timeStarted = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
//string[] dataValues = new string[(int)seconds];
List<string> dataValues = new List<string>();
var hubConnection = new HubConnection("http://localhost/PerfMon2/");
hubConnection.Credentials = CredentialCache.DefaultNetworkCredentials;
var perfMon = hubConnection.CreateProxy("LiveHub");
// perfMon.On("sendValue", message => Console.WriteLine(message));
perfMon.On("showValue", json => Console.WriteLine(json));
hubConnection.Start().Wait();
List<DataValueInfo> lol = new List<DataValueInfo>();
for (int i = 0; i < seconds; i++)
{
data = "Value " + i + ": " + perfCounter.NextValue().ToString();
//dataValues[i] = data;
dataValues.Add(data);
lol.Add(new DataValueInfo
{
Value = perfCounter.NextValue().ToString()
});
// perfMon.Invoke<List<DataValueInfo>>("Send", lol);
perfMon.Invoke("SendToClient", lol);
Thread.Sleep(1000);
}
string timeFinished = DateTime.Now.ToString("MM/dd/yyyy - h:mm:ss tt");
Log log = new Log
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = string.Join(",", dataValues),
UserID = currUser[0].UserID
};
this.CreateLog(log);
logIt.Add(new LogInfo
{
LogName = logName,
CounterName = perfCounter.CounterName,
InstanceName = perfCounter.InstanceName,
CategoryName = perfCounter.CategoryName,
MachineName = perfCounter.MachineName,
TimeStarted = timeStarted,
TimeFinished = timeFinished,
PerformanceData = dataValues.ToList<string>()
});
}
return logIt;
}
Here is the controller for the method in LogController.cs :
[AcceptVerbs("GET", "POST")]
public List<LogInfo> Log_Perf_Data(string machine_name, string category_name, string counter_name, string instance_name,
string log_name, long? seconds, string live, string enforceQuery)
{
LogController.CheckUser();
// POST api/log/post_data?machine_name=&category_name=&counter_name=&instance_name=&log_name=&seconds=
if (machine_name != null && category_name != null && counter_name != null && log_name != null && seconds.HasValue && enforceQuery == null)
{
List<LogInfo> dataVal = logDB.LogTimedPerfData(machine_name, category_name, counter_name, instance_name,
log_name, live, seconds);
logDB.SaveChanges();
return dataVal;
}
return new List<LogInfo>();
}
Maybe you can implement it in push technique. Here is how I do it:
Class with message
public class Message
{
/// <summary>
/// The name who will receive this message.
/// </summary>
public string RecipientName { get; set; }
/// <summary>
/// The message content.
/// </summary>
public string MessageContent { get; set; }
}
Class that will represent client:
public class Client
{
private ManualResetEvent messageEvent = new ManualResetEvent(false);
private Queue<Message> messageQueue = new Queue<Message>();
/// <summary>
/// This method is called by a sender to send a message to this client.
/// </summary>
/// <param name="message">the new message</param>
public void EnqueueMessage(Message message)
{
lock (messageQueue)
{
messageQueue.Enqueue(message);
// Set a new message event.
messageEvent.Set();
}
}
/// <summary>
/// This method is called by the client to receive messages from the message queue.
/// If no message, it will wait until a new message is inserted.
/// </summary>
/// <returns>the unread message</returns>
public Message DequeueMessage()
{
// Wait until a new message.
messageEvent.WaitOne();
lock (messageQueue)
{
if (messageQueue.Count == 1)
{
messageEvent.Reset();
}
return messageQueue.Dequeue();
}
}
}
Class to send messages to clients:
public class ClientAdapter
{
/// <summary>
/// The recipient list.
/// </summary>
private Dictionary<string, Client> recipients = new Dictionary<string,Client>();
/// <summary>
/// Send a message to a particular recipient.
/// </summary>
public void SendMessage(Message message)
{
if (recipients.ContainsKey(message.RecipientName))
{
Client client = recipients[message.RecipientName];
client.EnqueueMessage(message);
}
}
/// <summary>
/// Called by a individual recipient to wait and receive a message.
/// </summary>
/// <returns>The message content</returns>
public string GetMessage(string userName)
{
string messageContent = string.Empty;
if (recipients.ContainsKey(userName))
{
Client client = recipients[userName];
messageContent = client.DequeueMessage().MessageContent;
}
return messageContent;
}
/// <summary>
/// Join a user to the recipient list.
/// </summary>
public void Join(string userName)
{
recipients[userName] = new Client();
}
/// <summary>
/// Singleton pattern.
/// This pattern will ensure there is only one instance of this class in the system.
/// </summary>
public static ClientAdapter Instance = new ClientAdapter();
private ClientAdapter() { }
}
Sending messages:
Message message = new Message
{
RecipientName = tbRecipientName.Text.Trim(),
MessageContent = tbMessageContent.Text.Trim()
};
if (!string.IsNullOrWhiteSpace(message.RecipientName) && !string.IsNullOrEmpty(message.MessageContent))
{
// Call the client adapter to send the message to the particular recipient instantly.
ClientAdapter.Instance.SendMessage(message);
}
Receive messages (this is JavaScript functions written in test page. They render content of the message on ASPX page. Here you should implement your logic):
// This method will persist a http request and wait for messages.
function waitEvent() {
CSASPNETReverseAJAX.Dispatcher.WaitMessage("<%= Session["userName"] %>",
function (result) {
displayMessage(result);
// Keep looping.
setTimeout(waitEvent, 0);
}, function () {
// Keep looping.
setTimeout(waitEvent, 0);
});
}
// Append a message content to the result panel.
function displayMessage(message) {
var panel = document.getElementById("<%= lbMessages.ClientID %>");
panel.innerHTML += currentTime() + ": " + message + "<br />";
}
// Return a current time string.
function currentTime() {
var currentDate = new Date();
return currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds();
}
I'm trying to get the following to work on my machine but I get an error (Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader')
using System;
using System.IO;
using System.Reflection;
namespace com.companyname.business
{
/// <summary>
/// Summary description for SessionCreateRQClient.
/// </summary>
class SessionCreateRQClient
{
/// <summary>
/// The main entry point.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
// Set user information, including security credentials and the IPCC.
string username = "user";
string password = "password";
string ipcc = "IPCC";
string domain = "DEFAULT";
string temp = Environment.GetEnvironmentVariable("tmp"); // Get temp directory
string PropsFileName = temp + "/session.properties"; // Define dir and file name
DateTime dt = DateTime.UtcNow;
string tstamp = dt.ToString("s") + "Z";
//Create the message header and provide the conversation ID.
MessageHeader msgHeader = new MessageHeader();
msgHeader.ConversationId = "TestSession"; // Set the ConversationId
From from = new From();
PartyId fromPartyId = new PartyId();
PartyId[] fromPartyIdArr = new PartyId[1];
fromPartyId.Value = "WebServiceClient";
fromPartyIdArr[0] = fromPartyId;
from.PartyId = fromPartyIdArr;
msgHeader.From = from;
To to = new To();
PartyId toPartyId = new PartyId();
PartyId[] toPartyIdArr = new PartyId[1];
toPartyId.Value = "WebServiceSupplier";
toPartyIdArr[0] = toPartyId;
to.PartyId = toPartyIdArr;
msgHeader.To = to;
//Add the value for eb:CPAId, which is the IPCC.
//Add the value for the action code of this Web service, SessionCreateRQ.
msgHeader.CPAId = ipcc;
msgHeader.Action = "SessionCreateRQ";
Service service = new Service();
service.Value = "SessionCreate";
msgHeader.Service = service;
MessageData msgData = new MessageData();
msgData.MessageId = "mid:20001209-133003-2333#clientofsabre.com1";
msgData.Timestamp = tstamp;
msgHeader.MessageData = msgData;
Security security = new Security();
SecurityUsernameToken securityUserToken = new SecurityUsernameToken();
securityUserToken.Username = username;
securityUserToken.Password = password;
securityUserToken.Organization = ipcc;
securityUserToken.Domain = domain;
security.UsernameToken = securityUserToken;
SessionCreateRQ req = new SessionCreateRQ();
SessionCreateRQPOS pos = new SessionCreateRQPOS();
SessionCreateRQPOSSource source = new SessionCreateRQPOSSource();
source.PseudoCityCode = ipcc;
pos.Source = source;
req.POS = pos;
SessionCreateRQService serviceObj = new SessionCreateRQService();
serviceObj.MessageHeaderValue = msgHeader;
serviceObj.SecurityValue = security;
SessionCreateRS resp = serviceObj.SessionCreateRQ(req); // Send the request
if (resp.Errors != null && resp.Errors.Error != null)
{
Console.WriteLine("Error : " + resp.Errors.Error.ErrorInfo.Message);
}
else
{
msgHeader = serviceObj.MessageHeaderValue;
security = serviceObj.SecurityValue;
Console.WriteLine("**********************************************");
Console.WriteLine("Response of SessionCreateRQ service");
Console.WriteLine("BinarySecurityToken returned : " + security.BinarySecurityToken);
Console.WriteLine("**********************************************");
string ConvIdLine = "convid="+msgHeader.ConversationId; // ConversationId to a string
string TokenLine = "securitytoken="+security.BinarySecurityToken; // BinarySecurityToken to a string
string ipccLine = "ipcc="+ipcc; // IPCC to a string
File.Delete(PropsFileName); // Clean up
TextWriter tw = new StreamWriter(PropsFileName); // Create & open the file
tw.WriteLine(DateTime.Now); // Write the date for reference
tw.WriteLine(TokenLine); // Write the BinarySecurityToken
tw.WriteLine(ConvIdLine); // Write the ConversationId
tw.WriteLine(ipccLine); // Write the IPCC
tw.Close();
//Console.Read();
}
}
catch(Exception e)
{
Console.WriteLine("Exception Message : " + e.Message );
Console.WriteLine("Exception Stack Trace : " + e.StackTrace);
Console.Read();
}
}
}
}
I have added the reference System.ServiceModel and the lines:
using System.ServiceModel;
using System.ServiceModel.Channels;
but I continue to get that error when trying to compile --
Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader'
I am using Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
Professional Edition
Is there another reference I have to add? Or a dll to move over?
I wonder was the code above written for Framework 2.0 only?
Thanks for your help.
The error message is correct, you cannot create an instance of that class, it is declared abstract.
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messageheader.aspx
See if the static method MessageHeader.CreateHeader will work for you. Note there is several overloads, so pick the best one for you.