I am using GoogleAnalyticsTracker which works great and I am getting analytics reports for usage in my WinForms app.
However, every hit creates a new unique user session in Google Analytics and I would like to show unique users to give an idea of how many users are using my app.
I have read a section in the instructions but I am unsure how I implement the interface - I understand the basics of using an interface but this is something I would like to learn more here.
From the official website sessions are documented as follows:
Sessions are also untracked: every event that is tracked counts as a
new unique visitor to Google Analytics.
If you do need to track user sessions, implement a custom IAnalyticsSession and pass it to the constructor of the Tracker
object.
I would like to know how I can implement a custom IAnalyticsSession and pass it to the constructor of the Tracker object to my code below:
public class CommonTracking : IAnalyticsSession
{
static string googleID = "UA-######-##";
public string GenerateCacheBuster()
{
throw new NotImplementedException();
}
public string GenerateSessionId()
{
throw new NotImplementedException();
}
public static void TrackFeature()
{
// Get calling method name
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
TrackFeature(methodBase.Name);
}
public static async void TrackFeature(string FeatureCustom)
{
SimpleTrackerEnvironment trackerEnvironment = new SimpleTrackerEnvironment(Environment.OSVersion.Platform.ToString(),
Environment.OSVersion.Version.ToString(),
Environment.OSVersion.VersionString);
// Overwrite platform details
KeyValuePair<string, string> kvpOSSpecs = GetOperatingSystemProductName();
trackerEnvironment.OsPlatform = kvpOSSpecs.Key;
trackerEnvironment.OsVersion = kvpOSSpecs.Value;
SimpleTracker tracker = new SimpleTracker(googleID, trackerEnvironment);
await tracker.TrackPageViewAsync(System.AppDomain.CurrentDomain.FriendlyName, FeatureCustom, null);
}
static KeyValuePair<string, string> GetOperatingSystemProductName()
{
KeyValuePair<string, string> OperatingSystemSpec = new KeyValuePair<string, string>();
ManagementObjectSearcher wmiOsInfo = new ManagementObjectSearcher("SELECT Caption, Version FROM Win32_OperatingSystem");
try
{
foreach (var os in wmiOsInfo.Get())
{
var version = os["Version"].ToString();
var productName = os["Caption"].ToString();
OperatingSystemSpec = new KeyValuePair<string, string>(productName, version);
}
}
catch { }
return OperatingSystemSpec;
}
}
Problem solved...
public class GoogleTracking : IAnalyticsSession
{
static string _GoogleAnayticsPropertyID = string.Empty;
static AnalyticsSession _Session = new AnalyticsSession();
static Dictionary<int, string> _CustomDimensions = new Dictionary<int, string>();
static int iVal = 0;
public GoogleTracking(string googleID)
{
_GoogleAnayticsPropertyID = googleID;
}
public string GenerateCacheBuster()
{
return _Session.GenerateCacheBuster();
}
public string GenerateSessionId()
{
return _Session.GenerateSessionId();
}
public void UserDefined(string strUserVal)
{
_CustomDimensions.Add(iVal++, strUserVal);
}
public static void TrackFeature()
{
StackTrace stackTrace = new StackTrace();
MethodBase methodBase = stackTrace.GetFrame(1).GetMethod();
TrackFeature(methodBase.Name);
}
public static async void TrackFeature(string FeatureCustom)
{
if (!string.IsNullOrEmpty(_GoogleAnayticsPropertyID))
{
SimpleTrackerEnvironment trackerEnvironment = new SimpleTrackerEnvironment(Environment.OSVersion.Platform.ToString(),
Environment.OSVersion.Version.ToString(),
Environment.OSVersion.VersionString);
// Overwrite platform details
KeyValuePair<string, string> kvpOSSpecs = GetOperatingSystemProductName();
trackerEnvironment.OsPlatform = kvpOSSpecs.Key;
trackerEnvironment.OsVersion = kvpOSSpecs.Value;
SimpleTracker tracker = new SimpleTracker(_GoogleAnayticsPropertyID, _Session, trackerEnvironment);
await tracker.TrackPageViewAsync(System.AppDomain.CurrentDomain.FriendlyName, FeatureCustom, _CustomDimensions);
}
}
static KeyValuePair<string, string> GetOperatingSystemProductName()
{
KeyValuePair<string, string> OperatingSystemSpec = new KeyValuePair<string, string>();
ManagementObjectSearcher wmiOsInfo = new ManagementObjectSearcher("SELECT Caption, Version FROM Win32_OperatingSystem");
try
{
foreach (var os in wmiOsInfo.Get())
{
var version = os["Version"].ToString();
var productName = os["Caption"].ToString();
OperatingSystemSpec = new KeyValuePair<string, string>(productName, version);
}
}
catch (Exception ex)
{
Messagebox.Show(ex);
}
return OperatingSystemSpec;
}
}
Related
I am uploading files to a Gdrive follow this instructions. In the File objtect I just set the name, like this:
{
"name": "myObjectName"
}
The files are uploading without problem. Now I need to generate a shared link for each upload file, Do you know who is the request that I have to do?
Thanks,
With #Jacques-Guzel Heron´s help, I completed the upload file process. I created a wrapper for Google Drive API v3. That is my code if any need to do something like that: (I am using C#):
public interface IGDriveApiV3Wrapper
{
string UploadFile(string filePath, string gDriveUploadDestinationFolderId = null);
bool SetFilePermissions(string fileId, GDriveFileRole gDriveRole, GDriveFileType gDriveType);
GDriveFile GetFileInfo(string fileId);
}
public class GDriveApiV3NativeWrapper : IGDriveApiV3Wrapper
{
private const string GDriveFilesApiResumablePath = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
private const string GDriveTokenApiPath = "https://oauth2.googleapis.com/token";
private static readonly HttpClient GDriveClient = new HttpClient { Timeout = Timeout.InfiniteTimeSpan };
private readonly List<KeyValuePair<string, string>> _getTokenRequestContent;
private static GDriveTokenInfo _gDriveTokenInfo;
private static readonly object UpdateGDriveTokenInfoLocker = new object();
public GDriveApiV3NativeWrapper(string gDriveApiClientId, string gDriveApiClientSecret, string gDriveApiRefreshToken)
{
_getTokenRequestContent = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", gDriveApiClientId),
new KeyValuePair<string, string>("client_secret", gDriveApiClientSecret),
new KeyValuePair<string, string>("refresh_token", gDriveApiRefreshToken),
new KeyValuePair<string, string>("grant_type", "refresh_token")
};
}
public string UploadFile(string filePath, string gDriveUploadDestinationFolderId = null)
{
if (string.IsNullOrEmpty(filePath))
throw new ArgumentException("Value cannot be null or empty.", nameof(filePath));
FileInfo fileInfo;
try
{
fileInfo = new FileInfo(filePath);
}
catch (Exception ex)
{
throw new ArgumentException("File not valid.", nameof(filePath), ex);
}
if (!fileInfo.Exists)
throw new ArgumentException("File not exists.", nameof(filePath));
using (var initiateResumableUploadSessionRequest = new HttpRequestMessage(HttpMethod.Post, GDriveFilesApiResumablePath))
{
UpdateGDriveTokenInfo();
initiateResumableUploadSessionRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
var jsonContent = new JObject(
new JProperty("name", fileInfo.Name));
if (!string.IsNullOrEmpty(gDriveUploadDestinationFolderId))
{
jsonContent.Add(new JProperty("parents", new JArray { gDriveUploadDestinationFolderId }));
}
initiateResumableUploadSessionRequest.Content = new StringContent(jsonContent.ToString(), Encoding.UTF8, "application/json");
var initiateResumableUploadSessionResponse = GDriveClient.SendAsync(initiateResumableUploadSessionRequest).Result;
if (initiateResumableUploadSessionResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(initiateResumableUploadSessionResponse.ToString());
using (var uploadFileRequest = new HttpRequestMessage(HttpMethod.Put, initiateResumableUploadSessionResponse.Headers.Location))
{
uploadFileRequest.Content = new ByteArrayContent(File.ReadAllBytes(filePath));
HttpResponseMessage uploadFileResponse;
uploadFileResponse = GDriveClient.SendAsync(uploadFileRequest).Result;
if (uploadFileResponse.StatusCode != HttpStatusCode.OK && uploadFileResponse.StatusCode != HttpStatusCode.Created)
throw new ExternalException(uploadFileResponse.ReasonPhrase);
var uploadFileResponseBody = uploadFileResponse.Content.ReadAsStringAsync().Result;
JObject uploadFileResponseJson = JObject.Parse(uploadFileResponseBody);
return uploadFileResponseJson["id"].ToString();
}
}
}
public bool SetFilePermissions(string fileId, GDriveFileRole gDriveFileRole, GDriveFileType gDriveFileType)
{
if (string.IsNullOrEmpty(fileId))
throw new ArgumentException("Value cannot be null or empty.", nameof(fileId));
using (var setFilePermissionsRequest = new HttpRequestMessage(HttpMethod.Post, $"https://www.googleapis.com/drive/v3/files/{fileId}/permissions"))
{
UpdateGDriveTokenInfo();
setFilePermissionsRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
var jsonContent2 = new JObject(
new JProperty("role", gDriveFileRole.ToString().ToLower()),
new JProperty("type", gDriveFileType.ToString().ToLower()));
setFilePermissionsRequest.Content = new StringContent(jsonContent2.ToString(), Encoding.UTF8, "application/json");
HttpResponseMessage setFilePermissionsResponse = GDriveClient.SendAsync(setFilePermissionsRequest).Result;
if (setFilePermissionsResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(setFilePermissionsResponse.ToString());
}
return true;
}
public GDriveFile GetFileInfo(string fileId)
{
using (var getFileInfoRequest = new HttpRequestMessage(HttpMethod.Get, $"https://www.googleapis.com/drive/v3/files/{fileId}?fields=name,webViewLink"))
{
UpdateGDriveTokenInfo();
getFileInfoRequest.Headers.Authorization = new AuthenticationHeaderValue(_gDriveTokenInfo.TokenType, _gDriveTokenInfo.AccessToken);
HttpResponseMessage getFileInfoResponse = GDriveClient.SendAsync(getFileInfoRequest).Result;
if (getFileInfoResponse.StatusCode != HttpStatusCode.OK)
throw new ExternalException(getFileInfoResponse.ToString());
var getFileInfoResponseBody = getFileInfoResponse.Content.ReadAsStringAsync().Result;
JObject getFileInfoResponseJson = JObject.Parse(getFileInfoResponseBody);
return new GDriveFile
{
Id = fileId,
Name = getFileInfoResponseJson["name"].ToString(),
WebViewLink = getFileInfoResponseJson["webViewLink"].ToString()
};
}
}
private void UpdateGDriveTokenInfo()
{
lock (UpdateGDriveTokenInfoLocker)
{
if (_gDriveTokenInfo != null && !_gDriveTokenInfo.IsExpired())
{
return;
}
using (var refreshTokenRequest = new HttpRequestMessage(HttpMethod.Post, GDriveTokenApiPath))
{
refreshTokenRequest.Content = new FormUrlEncodedContent(_getTokenRequestContent);
var getTokenRequestResponse = GDriveClient.SendAsync(refreshTokenRequest).Result;
var jsonResponse = JObject.Parse(getTokenRequestResponse.Content.ReadAsStringAsync().Result);
_gDriveTokenInfo = new GDriveTokenInfo((string)jsonResponse["access_token"], (int)jsonResponse["expires_in"], (string)jsonResponse["token_type"]);
}
}
}
public class GDriveFile
{
public string Id { get; set; }
public string Name { get; set; }
public string WebViewLink { get; set; }
}
public enum GDriveFileRole
{
Owner,
Organizer,
FileOrganizer,
Writer,
Commenter,
Reader
}
public enum GDriveFileType
{
User,
Group,
Domain,
Anyone
}
public class Program
{
private static IGDriveApiV3Wrapper _gDriveApiV3Wrapper;
private readonly string _gDriveUploadDestinationFolderId;
public Program(IGDriveApiV3Wrapper gDriveApiV3Wrapper, string gDriveUploadDestinationFolderId = null)
{
_gDriveApiV3Wrapper = gDriveApiV3Wrapper;
_gDriveUploadDestinationFolderId = gDriveUploadDestinationFolderId;
}
public string Upload(string filePath)
{
string fileId = _gDriveApiV3Wrapper.UploadFile(filePath, _gDriveUploadDestinationFolderId);
_gDriveApiV3Wrapper.SetFilePermissions(fileId, GDriveFileRole.Reader, GDriveFileType.Anyone);
GDriveFile gDriveFile = _gDriveApiV3Wrapper.GetFileInfo(fileId);
return gDriveFile.WebViewLink;
}
}
I'll assume that you are using Drive API v3. To set up permissions after uploading the file you have to use the method create. You can check the sharing documentation to know more about the different ways of creation of permissions and its different levels of access. After sharing the file, you can retrieve the link with the property webViewLink of the file. If you still have any doubts, please ask me for further clarification.
The Class GDrivenTokenInfo i don`t see its code
I want to get information from only 1 user out of 20,000 users. The response time of the method I used below is 40 seconds. What is the solution to this problem?
public AuthenticatedUserProperties Info(string Username)
{
try
{
var context = new PrincipalContext(ContextType.Domain, Settings.LDAPDomain, Settings.LDAPContainer, Settings.LDAPUsername, Settings.LDAPPassword);
UserPrincipal user = new UserPrincipal(context);
user.SamAccountName = Username;
var searcher = new PrincipalSearcher(user);
var searchResults = searcher.FindOne();
DirectoryEntry de = searchResults.GetUnderlyingObject() as DirectoryEntry;
ActiveDirectoryUserProperties prop = ConvertLdapUserPropertyToArray(de);
return new AuthenticatedUserProperties
{
Status = true,
Properties = prop
};
}
catch (Exception e)
{
return new AuthenticatedUserProperties
{
Status = false,
Properties = null
};
}
}
I use the System.DirectoryServices.Protocols library instead. It is always blazing fast. I can never get System.DirectoryServices.AccountManagement to have reliable performance and it is often agonizingly slow (10+ seconds) to get just one user. TBH - I think our Network setup is likely to blame causing the bind to be dysfunctional - but the Protocols library yields good results without much effort regardless of our network dysfunction.
You have to do slightly more work - but nothing particularly difficult. I'm not an expert with this library - but this sample code works reliably for me.
using System.DirectoryServices.Protocols;
public class UserInfo
{
public string SAMAccountName;
public string DomainHostName;
public string ADSDirectory;
public Dictionary<string, string> UserAttributes;
// Some attributes not really strings and require extra handling - but simplied for example
// This is really just for illustrative purposes
public UserInfo(string a_SAMAccountName, string a_DomainHostName = "ldap.mydomain:3268", string a_ADSDirectory = "ours.net")
{
UserAttributes = new Dictionary<string, string>();
SAMAccountName = a_SAMAccountName;
DomainHostName = a_DomainHostName;
ADSDirectory = a_ADSDirectory;
}
}
public static class GetUserAttributes
{
public static List<string> WantedAttributes;
static GetUserAttributes()
{
WantedAttributes = new List<string>();
WantedAttributes.Add("mail");
//... Add Properties Wanted
}
public static void GetUserAttributes(UserInfo a_user)
{
using (HostingEnvironment.Impersonate())
{
LdapDirectoryIdentifier z_entry = new LdapDirectoryIdentifier(a_user.DomainHostName, true, false);
using (LdapConnection z_remote = new LdapConnection(z_entry))
{
z_remote.SessionOptions.VerifyServerCertificate = delegate (LdapConnection l, X509Certificate c) { return true; };
z_remote.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
z_remote.SessionOptions.ProtocolVersion = 3;
z_remote.Bind();
SearchRequest z_search = new SearchRequest();
z_search.Scope = System.DirectoryServices.Protocols.SearchScope.Subtree;
z_search.Filter = "(SAMAccountName=" + a_user.SAMAccountName + ")";
z_search.DistinguishedName = a_user.ADSdirectory;
foreach (List<string> z_item in WantedAttributes)
{
z_search.Attributes.Add(z_item);
}
SearchResponse z_response = (SearchResponse)z_remote.SendRequest(z_search);
if (z_response != null)
{
foreach (SearchResultEntry z_result in z_response.Entries)
{
foreach (string z_property in z_result.Attributes.AttributeNames)
{
if (WantedAttributes.ContainsKey(z_property))
{
DirectoryAttribute z_details = a_result.Attributes[z_property];
if (z_details.Count == 1)
{
// Special handling required for Attributes that aren't strings objectSid, objectGUID, etc
string z_value = z_details[0].ToString().Trim();
if (!string.IsNullOrWhiteSpace(z_value))
{
a_user.UserAttributes.Add(z_property, z_value);
}
}
}
}
}
}
}
}
}
}
I need to upgrade code calling IronPython from C# and would like to upgrade to IronPython 2.7.5. The problem is that one of the APIs has changed, and I am not familiar enough with the original code to fix it. I have written a console program that exhibits the problem
My Main:
class Program
{
static void Main()
{
var pythonTest = new PythonTest();
pythonTest.LoadScript();
Console.WriteLine("Area = {0}", pythonTest.Evaluate());
}
}
My test class:
public class PythonTest
{
private readonly ScriptEngine _engine;
private readonly ScriptScope _scope;
private ScriptSource _source;
private PythonFunction _currentFunction;
private readonly Dictionary<string, PythonFunction> _functions = new Dictionary<string, PythonFunction>();
private readonly double _scriptInput;
public PythonTest()
{
_scriptInput = 5;
_engine = Python.CreateEngine();
_scope = _engine.CreateScope();
}
public void LoadScript()
{
const string filename = #"../../Scripts/testscript.py";
_source = _engine.CreateScriptSourceFromFile(filename);
_source.Execute(_scope);
string firstFunction = "";
foreach (KeyValuePair<string, object> pair in _scope.GetItems())
{
var pairValue = pair.Value as PythonFunction;
if (pairValue != null)
{
_functions.Add(pair.Key, pairValue);
if (_functions.Count == 1)
{
firstFunction = _functions.Keys.First();
}
}
}
_currentFunction = _functions[firstFunction];
}
public string Evaluate()
{
if (_currentFunction == null)
return null;
var parameters = new ArrayList {_scriptInput};
LanguageContext cxt = Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(_engine);
var context = new CodeContext(new Scope(), cxt);
object result = _currentFunction.__call__(context, parameters.ToArray());
return result.ToString();
}
}
My test script:
from math import *
def AREA(h):
return (h * h)
This all works with the old Python DLLs. With the new DLLs the instantiation of the CodeContext (in the Evaluate method) is incorrect. The new API uses a PythonDictionary:
public CodeContext(PythonDictionary dict, ModuleContext moduleContext);
I don't know how to modify the code to fix this problem. Any help would be appreciated.
Your LanguageContext is a PythonContext so it can be cast. You can then use that along with a PythonDictionary to create a ModuleContext. Then you can use that along with a PythonDictionary to create your CodeContext:
PythonContext cxt = (PythonContext)Microsoft.Scripting.Hosting.Providers.HostingHelpers.GetLanguageContext(_engine);
PythonDictionary dict = new PythonDictionary();
ModuleContext modctx = new ModuleContext(dict, cxt);
var context = new CodeContext(dict, modctx);
Ninject doesn’t provide a InSessionScope Binding for Websites, so we have created our own extension:
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
if (HttpContext.Current.Session[_sessionKey] == null)
{
HttpContext.Current.Session[_sessionKey] = new object();
}
return HttpContext.Current.Session[_sessionKey];
}
This extension is working fine until we are using the standard local SessionStore.
But we changed the SessionStore and we now use the „AppFabricCacheSessionStoreProvider“ and this store is no longer on the local machine its on the server.
And the problem is that Ninject tries to resolve the reference of an object which was serialized and deserialized and comes from the server and not from the local memory and so ninject can’t find the reference. The result is, that ninjects allways creates a new Object and the SessionScope does not work any more.
Edit 1:
We are using this functionality
https://msdn.microsoft.com/en-us/library/hh361711%28v=azure.10%29.aspx
and here I can use the standard "HttpContext.Current.Session" Object and the list content is stored on the server and not on the local machine.
So architecturally you have a problem in that you need to store the settings for AppFabric somewhere, and this is an issue with your static method. But assume you create a public static class like so:
public static class AppCache
{
public static DataCache Cache { get; private set; }
static AppCache()
{
List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>(1);
servers.Add(new DataCacheServerEndpoint("ServerName", 22233)); //22233 is the default port
DataCacheFactoryConfiguration configuration = new DataCacheFactoryConfiguration
{
Servers = servers,
LocalCacheProperties = new DataCacheLocalCacheProperties(),
SecurityProperties = new DataCacheSecurity(),
RequestTimeout = new TimeSpan(0, 0, 300),
MaxConnectionsToServer = 10,
ChannelOpenTimeout = new TimeSpan(0, 0, 300),
TransportProperties = new DataCacheTransportProperties() { MaxBufferSize = int.MaxValue, MaxBufferPoolSize = long.MaxValue }
};
DataCacheClientLogManager.ChangeLogLevel(System.Diagnostics.TraceLevel.Off);
var _factory = new DataCacheFactory(configuration);
Cache = _factory.GetCache("MyCache");
}
}
then you can change extension like so:
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
var cachedItem = AppCache.Cache.Get("MyItem"); // IMPORTANT: For concurrency reason, get the whole item down to method scope.
if (cachedItem == null)
{
cachedItem = new object();
AppCache.Cache.Put("MyItem", cachedItem);
}
return cachedItem;
}
I've found a "Solution" that works so far it's not perfect because I am avoiding the AppFabric Store with an Localstore for the Object Reference.
public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
{
return parent.InScope(SessionScopeCallback);
}
public static Dictionary<string, object> LocalSessionStore = new Dictionary<string, object>();
private const string _sessionKey = "Ninject Session Scope Sync Root";
private static object SessionScopeCallback(IContext context)
{
var obj = new object();
var key = (string)HttpContext.Current.Session[_sessionKey];
if (string.IsNullOrEmpty(key))
{
var guid = Guid.NewGuid().ToString();
HttpContext.Current.Session[_sessionKey] = guid;
LocalSessionStore.Add(guid, obj);
}
else if(!LocalSessionStore.ContainsKey(key))
{
LocalSessionStore.Add(key, obj);
return LocalSessionStore[key];
}
else if (LocalSessionStore.ContainsKey(key))
{
return LocalSessionStore[key];
}
return HttpContext.Current.Session[_sessionKey];
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I'm writing multithreading program for reading and viewing in comfortable form Apache log files. It works, but it doesn't work correctly on an one-core processor. I assume where is error in, but I don't know what I need to change. Assuming error has been written in comment.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using System.Data;
using System.Text.RegularExpressions;
namespace lab2Form
{
class LogStruct
{
public Dictionary<string, ulong> domainName;
public Dictionary<string, ulong> URL;
public Dictionary<string, ulong> domainData;
public Dictionary<string, ulong> errorCodes;
public LogStruct()
{
domainName = new Dictionary<string, ulong> { };
URL = new Dictionary<string, ulong> { };
domainData = new Dictionary<string, ulong> { };
errorCodes = new Dictionary<string, ulong> { };
}
}
class CLogParser
{
LogStruct m_logStruct;
public CLogParser()
{
m_logStruct = new LogStruct();
}
public void ThreadProc(object param)
{
string logName = (string)param;
StreamReader file;
try
{
file = new StreamReader(logName);
}
catch
{
return;
}
string line;
while ((line = file.ReadLine()) != null)//may be,something wrong here
{
var space_pos = line.IndexOf(' ');
if (space_pos > 0)
{
string[] parameters = line.Split(new Char[] { ' '}, StringSplitOptions.RemoveEmptyEntries);
string domainName = parameters[0];
bool isMainPage = (parameters[4] == "\"-\"") ? true : false;
string relativePageAddress = (isMainPage) ? "/" : parameters[5];
Regex reg = new Regex(" \\d+");
MatchCollection matches = reg.Matches(line);
string errorCode = matches[1].Value;
ulong pageSize = (matches.Count > 2) ? Convert.ToUInt64(matches[2].Value) : 0;
string fullAdress = domainName + relativePageAddress;
string fullErrCode = domainName + errorCode;
if (m_logStruct.domainName.ContainsKey(domainName))
{
lock (m_logStruct.domainName)
{
m_logStruct.domainName[domainName]++;
}
lock (m_logStruct.domainData)
{
m_logStruct.domainData[domainName] += pageSize;
}
if (m_logStruct.URL.ContainsKey(fullAdress))
{
lock (m_logStruct.URL)
{
m_logStruct.URL[fullAdress]++;
}
}
else
{
lock (m_logStruct.URL)
{
m_logStruct.URL.Add(fullAdress, 1);
}
}
if (m_logStruct.errorCodes.ContainsKey(fullErrCode))
{
lock (m_logStruct.errorCodes)
{
m_logStruct.errorCodes[fullErrCode]++;
}
}
else
{
lock (m_logStruct.errorCodes)
{
m_logStruct.errorCodes.Add(fullErrCode, 1);
}
}
}
else
{
lock (m_logStruct.domainName)
{
m_logStruct.domainName.Add(domainName, 1);
}
lock (m_logStruct.URL)
{
m_logStruct.domainData.Add(domainName, pageSize);
}
lock (m_logStruct.domainData)
{
m_logStruct.URL.Add(fullAdress, 1);
}
lock (m_logStruct.errorCodes)
{
m_logStruct.errorCodes.Add(fullErrCode, 1);
}
}
}
}
}
public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes)
{
List<KeyValuePair<string, ulong>> dmReqList = new List<KeyValuePair<string, ulong>>();
List<KeyValuePair<string, ulong>> urlReqList = new List<KeyValuePair<string, ulong>>();
List<KeyValuePair<string, ulong>> dmDataList = new List<KeyValuePair<string, ulong>>();
List<KeyValuePair<string, ulong>> errCodesList = new List<KeyValuePair<string, ulong>>();
lock (m_logStruct.domainName)`enter code here`
{
dmReqList = m_logStruct.domainName.ToList();
}
lock(m_logStruct.URL)
{
urlReqList = m_logStruct.URL.ToList();
}
lock(m_logStruct.domainData)
{
dmDataList = m_logStruct.domainData.ToList();
}
lock(m_logStruct.errorCodes)
{
errCodesList = m_logStruct.errorCodes.ToList();
}
dmRequests.DataSource = dmReqList.OrderBy(x => x.Key).ToList();
URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList();
dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList();
errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList();
}
}
}
You're accessing shared state from multiple threads in a racy way with at least one of them being a writer.
Example:
if (m_logStruct.URL.ContainsKey(fullAdress)) //unsynchronized read
The rules of threading say that you cannot safely do that.
I don't see what's supposed to be wrong with the line you marked. The stream is thread-local. It is not being used in a racy way.
Why don't you use the ConcurrentDictionary of .NET4? The hard work of ensuring thread safety in dictionaries has already been done. Your code would be much cleaner and less error prone. Maybe it solves your problem, maybe it doesn't. (You still haven't described the symptoms of "not working". Does it run as a single-threaded app? Does it crash? Does it produce wrong data?)
class LogStruct
{
public ConcurrentDictionary<string, ulong> domainName;
public ConcurrentDictionary<string, ulong> URL;
public ConcurrentDictionary<string, ulong> domainData;
public ConcurrentDictionary<string, ulong> errorCodes;
public LogStruct()
{
domainName = new ConcurrentDictionary<string, ulong> { };
URL = new ConcurrentDictionary<string, ulong> { };
domainData = new ConcurrentDictionary<string, ulong> { };
errorCodes = new ConcurrentDictionary<string, ulong> { };
}
}
class CLogParser
{
LogStruct m_logStruct;
public CLogParser()
{
m_logStruct = new LogStruct();
}
public void ThreadProc(object param)
{
string logName = (string)param;
StreamReader file;
try
{
file = new StreamReader(logName);
}
catch
{
return;
}
string line;
while ((line = file.ReadLine()) != null)//may be,something wrong here
{
var space_pos = line.IndexOf(' ');
if (space_pos > 0)
{
string[] parameters = line.Split(new Char[] { ' '}, StringSplitOptions.RemoveEmptyEntries);
string domainName = parameters[0];
bool isMainPage = (parameters[4] == "\"-\"") ? true : false;
string relativePageAddress = (isMainPage) ? "/" : parameters[5];
Regex reg = new Regex(" \\d+");
MatchCollection matches = reg.Matches(line);
string errorCode = matches[1].Value;
ulong pageSize = (matches.Count > 2) ? Convert.ToUInt64(matches[2].Value) : 0;
string fullAdress = domainName + relativePageAddress;
string fullErrCode = domainName + errorCode;
if (m_logStruct.domainName.ContainsKey(domainName))
{
m_logStruct.domainName[domainName]++;
m_logStruct.domainData[domainName] += pageSize;
m_logStruct.URL.AddOrUpdate(fullAdress, 1, (key, oldVal) =>
{
m_logStruct.URL[fullAdress]++;
return m_logStruct.URL[fullAdress];
});
m_logStruct.errorCodes.AddOrUpdate(fullErrCode, 1, (key, oldVal) =>
{
m_logStruct.errorCodes[fullErrCode]++;
return m_logStruct.errorCodes[fullErrCode];
});
}
else
{
m_logStruct.domainName.AddOrUpdate(domainName, 1, ShallNeverHappen);
m_logStruct.domainData.AddOrUpdate(domainName, pageSize, ShallNeverHappen);
m_logStruct.URL.AddOrUpdate(fullAdress, 1, ShallNeverHappen);
m_logStruct.errorCodes.AddOrUpdate(fullErrCode, 1, ShallNeverHappen);
}
}
}
}
public ulong ShallNeverHappen(String key, ulong existingVal)
{
throw new InvalidOperationException("This method is not expected to be called");
}
}