Forgive the lengthy code here, and I also realise this may be a very basic fundamental question for any object-oriented developer, but I'm a front-end developer in at the deep end with .NET and trying to learn about classes and methods with an actual example. I've read resources to explain this stuff but immediately get stuck with the complexities of real-world code.
Basically I have a bunch of methods for adding comments to a web page and manipulating the status (marking as spam, deleting etc). Many of these methods call an 'EmailNotification' method, which sends an email to an administrator at each stage. It works great.
However, I'd like to use the 'EmailNotification' method elsewhere in the project, calling it from a different .cs file. When I try to do this it doesn't recognise the method because (I think!?) it's not a public static method.
Can anyone explain to me how to extract the EmailNotification method so that I can use it in different places around the code? I have tried creating a new class with this method inside it, but I just can't get it to work.
using System;
using System.Net.Mail;
namespace UComment.Domain
{
public class Comment
{
public delegate void CommentCreatedEventHandler(Comment sender, EventArgs e);
public delegate void CommentDeletedEventHandler(Comment sender, EventArgs e);
public delegate void CommentSpamEventHandler(Comment sender, EventArgs e);
public delegate void CommentApprovedEventHandler(Comment sender, EventArgs e);
public static event CommentCreatedEventHandler CommentCreated;
public static event CommentDeletedEventHandler CommentDeleted;
public static event CommentSpamEventHandler CommentSpam;
public static event CommentApprovedEventHandler CommentApproved;
protected virtual void OnCommentCreated(EventArgs e)
{
if (CommentCreated != null) CommentCreated(this, e);
}
protected virtual void OnCommentSpam(EventArgs e)
{
if (CommentSpam != null) CommentSpam(this, e);
}
protected virtual void OnCommentApproved(EventArgs e)
{
if (CommentApproved != null) CommentApproved(this, e);
}
protected virtual void OnCommentDelete(EventArgs e)
{
if (CommentDeleted != null) CommentDeleted(this, e);
}
public int Id { get; set; }
public int ParentNodeId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public bool Spam { get; set; }
public bool Approved { get; set; }
public DateTime Created { get; set; }
public string CommenText { get; set; }
public int StatusId { get; set; }
public Comment(int id)
{
Id = id;
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
var reader = sqlHelper.ExecuteReader("select * from Comment where id = #id",
sqlHelper.CreateParameter("#id", id));
if(!reader.HasRecords) throw new Exception(string.Format("Comment with id {0} was not found", id));
reader.Read();
Name = reader.GetString("name");
ParentNodeId = reader.GetInt("nodeid");
Email = reader.GetString("email");
Website = reader.GetString("website");
Approved = reader.GetBoolean("approved");
Spam = reader.GetBoolean("Spam");
Created = reader.GetDateTime("created");
CommenText = reader.GetString("comment");
StatusId = reader.GetInt("statusid");
}
private Comment()
{
}
/// <summary>
/// Set as approved, mark as Not Spam - ignore HAM status
/// </summary>
public void MarkAsApproved()
{
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery(
"update comment set approved = 1, spam = 0, statusid = 2 where id = #id",
sqlHelper.CreateParameter("#id", Id));
OnCommentApproved(EventArgs.Empty);
// Send approval email
EmailNotification(1);
}
/// <summary>
/// Remove approval status. Ignore Spam and Ham states
/// </summary>
public void MarkAsNotApproved()
{
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery(
"update comment set approved = 0, statusid = 3 where id = #id",
sqlHelper.CreateParameter("#id", Id));
OnCommentApproved(EventArgs.Empty);
// Send rejection email
EmailNotification(2);
}
/// <summary>
/// Spam cannot be ham or approved
/// </summary>
public void MarkAsSpam()
{
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery(
"update comment set spam = 1, ham = 0, approved = 0, statusid = 3 where id = #id",
sqlHelper.CreateParameter("#id", Id));
OnCommentSpam(EventArgs.Empty);
// No email notification required - spammer not worthy of a reason for rejection
}
/// <summary>
/// Ham is "not spam" - approved comments from Akismet.
/// </summary>
public void MarkAsHam()
{
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery(
"update comment set spam = 0, ham = 1 where id = #id",
sqlHelper.CreateParameter("#id", Id));
// No email notification required, simply marking spam as ham
}
public void Delete()
{
if (Id < 1) return;
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery("delete from comment where id = #id", sqlHelper.CreateParameter("#id", Id));
Id = -1;
OnCommentDelete(EventArgs.Empty);
// Permanent deletion
}
public void Reject()
{
if (Id < 1) return;
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
sqlHelper.ExecuteNonQuery("update comment set statusid = 3 where id = #id", sqlHelper.CreateParameter("#id", Id));
//Id = -1;
//OnCommentDelete(EventArgs.Empty);
// Send rejection email
EmailNotification(2);
}
public static Comment MakeNew(int parentNodeId, string name, string email, string website, bool approved, bool spam, DateTime created, string commentText, int statusId)
{
var c = new Comment
{
ParentNodeId = parentNodeId,
Name = name,
Email = email,
Website = website,
Approved = approved,
Spam = spam,
Created = created,
CommenText = commentText,
StatusId = statusId
};
var sqlHelper = DataLayerHelper.CreateSqlHelper(cms.GlobalSettings.DbDSN);
c.Id = sqlHelper.ExecuteScalar<int>(
#"insert into Comment(mainid,nodeid,name,email,website,comment,approved,spam,created,statusid)
values(#mainid,#nodeid,#name,#email,#website,#comment,#approved,#spam,#created,#statusid)",
sqlHelper.CreateParameter("#mainid", -1),
sqlHelper.CreateParameter("#nodeid", c.ParentNodeId),
sqlHelper.CreateParameter("#name", c.Name),
sqlHelper.CreateParameter("#email", c.Email),
sqlHelper.CreateParameter("#website", c.Website),
sqlHelper.CreateParameter("#comment", c.CommenText),
sqlHelper.CreateParameter("#approved", c.Approved),
sqlHelper.CreateParameter("#spam", c.Spam),
sqlHelper.CreateParameter("#created", c.Created),
sqlHelper.CreateParameter("#statusid", c.StatusId));
c.OnCommentCreated(EventArgs.Empty);
if (c.Spam)
{
c.OnCommentSpam(EventArgs.Empty);
}
if (c.Approved)
{
c.OnCommentApproved(EventArgs.Empty);
}
return c;
}
public override string ToString()
{
return #"ParentNodeId " + ParentNodeId + #"
Name " + Name + #"
Email " + Email + #"
Website " + Website + #"
Approved " + Approved + #"
Spam " + Spam + #"
Created "+ Created + #"
CommenText " + CommenText + Environment.NewLine;
}
/// <summary>
/// Send email notification
/// </summary>
public void EmailNotification(int notificationType)
{
var uCommentAdminEmail = Config.GetUCommentSetting("uCommentAdminEmail");
MailAddress to = null;
MailAddress from = new MailAddress(uCommentAdminEmail);
string subject = null;
string body = null;
switch (notificationType)
{
case 1:
// Comment approved
to = new MailAddress("me#mydomain.com");
subject = "Comment approved";
body = #"The comment you posted has been approved";
break;
case 2:
// Comment rejected
to = new MailAddress("me#mydomain.com");
subject = "Comment rejected";
body = #"The comment you posted has been rejected";
break;
}
MailMessage message = new MailMessage(from, to);
message.Subject = subject;
message.Body = body;
SmtpClient client = new SmtpClient();
try
{
client.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in EmailNotification: {0}", ex.ToString());
}
finally
{
//
}
}
}
}
Thanks for any pointers folks!
You can:
Extract it to a static method on static class
Create a singleton class that has an instance method
Create a class and interface for MessageSender and use DI to inject it where it's needed.
It depends on the size of the project: for small ones 1. may be enough, for big and complex (and if you have DI in place) 3 would be required.
What you have here is a public method, but because it's not declared as static (public static void EmailNotification...), it cannot be used without creating an instance of the class that it lives in.
using System;
namespace UComment.Domain
{
public class MyOtherClass
{
public void MyMethod()
{
Comment c = new Comment();
c.EmailNotification(1);
}
}
}
You could declare the method static which would let you call it like this:
using System;
namespace UComment.Domain
{
public class MyOtherClass
{
public void MyMethod()
{
Comment.EmailNotification(1);
}
}
}
If you're trying to use it from a different namespace then you would need to include the namespace either by a using statement or by specifying the full namespace inline.
using System;
using UComment.Domain;
namespace UComment.OtherNamespace
{
public class MyOtherClass
{
public void MyMethod()
{
Comment c = new Comment();
c.EmailNotification(1);
}
}
}
Or
using System;
namespace UComment.OtherNamespace
{
public class MyOtherClass
{
public void MyMethod()
{
UComment.Domain.Comment c = new UComment.Domain.Comment();
c.EmailNotification(1);
}
}
}
You are correct in thinking that if you wish to make this a common method, it should independent of the Comment class. The same limitations that I've just described apply to doing that. In addition, you'll have to make sure that any appropriate using statements are on the new class and that the dependencies within the EmailNotification are accounted for as well.
Your class makes too many things!
Split it in different types, each one has to solve only one type of problem according to Separation of concerns.
Same thing for the email sending, create an EmailSender class (or another name) and centralize the Send method there.
You can also create an interface (e.g. ISmtpClientFactory) to pass to the EmailSender class to abstract the concrete system to send emails and improve the testing experience.
Only on the production environment you really send emails, in the test environment you can use a fake factory to simulate the sending.
public class EmailSender
{
private readonly ISmtpClientFactory factory;
public EmailSender(ISmtpClientFactory factory)
{
this.factory = factory;
}
public void Send(MailMessage message)
{
using (var client = factory.Create())
{
using (message)
{
client.Send(message);
}
}
}
}
new EmailSender(new SmtpClientFactory()).Send(AdviceMessageFactory.Create(...));
You could put it in it's own class (like you already tried) and make the method static.
If this new class was EmailHelper, you would call the method like so:
EmailHelper.EmailNotification(1);
Depending on the namespace of the new class, you may also need a using statement at the top of every file you use it in.
It doesn't look like It should cause any issue If you create a (public) class and have that method in it. That method should accept all the properties it needs to send an email. You can create an instance of that class and call that method.
Related
for example:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrateState : MonoBehaviour, IStateQuery
{
public Transform crateCap;
public SaveLoad saveLoad;
public bool hasOpened;
private bool saveOnce = true;
private State m_state = new State();
public Guid UniqueId = new Guid();//=> Guid.Parse("D9687717-CEF7-4E6C-8318-20BCC51E0110");
private class State
{
public bool open;
}
public string GetState()
{
return JsonUtility.ToJson(m_state);
}
public void SetState(string jsonString)
{
m_state = JsonUtility.FromJson<State>(jsonString);
if (m_state.open)
{
crateCap.localRotation = Quaternion.Euler(90, 0, 0);
hasOpened = true;
}
else
{
crateCap.localRotation = Quaternion.Euler(180, 0, 0);
hasOpened = false;
}
}
// Update is called once per frame
void Update()
{
if (GetComponent<UnlockCrate>().HasOpened())
{
hasOpened = true;
if (saveOnce)
{
StartCoroutine(saveLoad.SaveWithTime());
saveOnce = false;
}
}
else
{
hasOpened = false;
}
m_state.open = hasOpened;
}
}
The line :
public Guid UniqueId = new Guid();
was :
public Guid UniqueId => Guid.Parse("D9687717-CEF7-4E6C-8318-20BCC51E0110");
but it's a bit annoying to do in the menu in the visual studio: Tools > Create GUID > and then generate a new guid and copy it to the script.
I'm using this script base for every object I want to save its state. and for that i need to generate a new guid.
I tried to change the line to:
public Guid UniqueId = new Guid();
but then getting error on the top at: IStateQuery
CrateState does not implement interface member IStateQuery.UniqueId
This is the IStateQuery class:
using System;
public interface IStateQuery
{
string GetState();
void SetState(string jsonString);
Guid UniqueId { get; }
}
i'm not sure if making instance like i'm doing now is the right way and how ot fix the error.
in the other hand i want to make something easier to generate each time a new guid number instead copying it manual to the state script.
I tried to make a new instance:
public Guid UniqueId = new Guid();
but this give me error on the IStateQuery so I'm not sure if this is the right approach.
Give this a shot:
[SerualizeField] private string _uniqueId = string.Empty;
public Guid UniqueId
{
get
{
if (string.IsNullOrEmpty(_uniqueId))
_uniqueId = Guid.NewGuid().ToString();
return Guid.Parse(_uniqueId);
}
}
Unity can’t serialise a Guid, but it can serialise a string. So, we can use a string as the underlying guid store. Unity could also serialise a byte[], which would be more efficient, especially if UniqueID is read many times. The code above is just the simplest to implement and easiest to understand, and if you’re serialising to JSON, then a string Id is likely going to be the most helpful.
You are initializing a read-only property using the Lambda operator.
Change
public Guid UniqueId => Guid.Parse("D9687717-CEF7-4E6C-8318-20BCC51E0110");
to
public Guid UniqueId => Guid.NewGuid();
Guid.NewGuid is a static method of the Guid Struct.
See also
Stack Overflow: C# how to create a Guid value?
I am new to the C# community. I created a controller and a class with the class containing some logic from a COM reference that I want to be executed.
When I call the API, it does not seem to be going into the ImportInventory method and no logic is executed in that public string (as seen from the debugging breakpoints).
Can someone please assist on how to get this part of the code executed? I am new to C# and can't seem to find the issue.
Code snippet of the controller:
using MDRDS_PastelIntegrator.Models;
using Microsoft.AspNetCore.Mvc;
namespace MDRDS_PastelIntegrator.Controllers
{
[ApiController]
[Route("[controller]")]
public class InventoryController : ControllerBase
{
private readonly ILogger<InventoryController> _logger;
public InventoryController(ILogger<InventoryController> logger)
{
_logger = logger;
}
[HttpPost(Name = "POSTInventory")]
public IEnumerable<POSTInventory> Get(string pParameter, string pPath)
{
return Enumerable.Range(1, 1).Select(index => new POSTInventory
{
Parameter = pParameter,
Path = pPath
})
.ToArray();
}
}
}
Code snippet of the class:
namespace MDRDS_PastelIntegrator.Models
{
public class POSTInventory
{
//public string? StrReturn;
public string? Parameter { get; set; }
public string? Path { get; set; }
public string ImportInventory(string Parameter, string Path)
{
var SDK = new PasSDK.PastelPartnerSDK();
//Set License
var F_GetLisence = new SetLicense();
F_GetLisence.MethodSetLicense();
//Set Data Path
var StrReturn = SDK.SetDataPath(Path);
if (StrReturn == "0")
{
var StrIn = Parameter;
var StrCodeIn = StrIn;
//Import Inventory Item
StrReturn = SDK.ImportInventory(StrIn);
};
//Blank return string - No serial number
if (StrReturn.Length == 0)
{
StrReturn = "Serial Number Not Specified.";
//return StrReturn;
};
//Get Result Code
if (StrReturn == "0")
{
StrReturn = "0 = Success";
}
else
{
StrReturn = "1 = Unsuccessfull";
};
return StrReturn;
}
}
}
You create an object POSTInventory but you never call the ImportInventory method of this object
This question already has answers here:
My console app shutdown prematurely when using async / await?
(4 answers)
Program exits upon calling await
(3 answers)
Closed 2 years ago.
Before you all go on a rampage about how this is a duplicate question, I have spent two days working on this issue, watching youtube tutorials on asynchronous programming, surfing similar stackoverflow posts etc, and I cannot for the life of me figure out how to apply Asynchronous Parallel Downloading of files into my project.
First things first, some background:
I am creating a program that, when given a query input via the user, will make a call to the twitch API and download clips.
My program is two parts
1- A web scraper that generates a .json file with all details needed to download files and
2 - A downloader.
Part 1 works perfectly fine and generates the .json files no trouble.
My Downloader contains reference to a Data class that is a handler for common properties and methods like my ClientID, Authentication, OutputPath, JsonFile, QueryURL. It also contains methods to give values to these properties.
Here are the two methods of my FileDownloader.cs that are the problem:
public async static void DownloadAllFiles(Data clientData)
{
data = clientData;
data.OutputFolderExists();
// Deserialize .json file and get ClipInfo list
List<ClipInfo> clips = JsonConvert.DeserializeObject<List<ClipInfo>>(File.ReadAllText(data.JsonFile));
tasks = new List<Task>();
foreach(ClipInfo clip in clips)
{
tasks.Add(DownloadFilesAsync(clip));
}
await Task.WhenAll(tasks);
}
private async static Task DownloadFilesAsync(ClipInfo clip)
{
WebClient client = new WebClient();
string url = GetClipURL(clip);
string filepath = data.OutputPath + clip.id + ".mp4";
await client.DownloadFileTaskAsync(new Uri(url), filepath);
}
This is only one of my many attempts of downloading files, one which I got the idea from this post:
stackoverflow_link
I have also tried methods like the following from a YouTube video by IAmTimCorey:
video_link
I have spent many an hour tackling this problem, and I honestly can't figure out why it won't work with any of my attempts. I would vastly appreciate your help.
Thanks,
Ben
Below is the entirety of my code, should anyone need it for any reason.
Code Structure:
The only external libraries I have downloaded is Newtonsoft.Json
ClipInfo.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace Downloader
{
public class ClipInfo
{
public string id { get; set; }
public string url { get; set; }
public string embed_url { get; set; }
public string broadcaster_id { get; set; }
public string broadcaster_name { get; set; }
public string creator_id { get; set; }
public string creator_name { get; set; }
public string video_id { get; set; }
public string game_id { get; set; }
public string language { get; set; }
public string title { get; set; }
public int view_count { get; set; }
public DateTime created_at { get; set; }
public string thumbnail_url { get; set; }
}
}
Pagination.cs
namespace Downloader
{
public class Pagination
{
public string cursor { get; set; }
}
}
Root.cs
using System.Collections.Generic;
namespace Downloader
{
public class Root
{
public List<ClipInfo> data { get; set; }
public Pagination pagination { get; set; }
}
}
Data.cs
using System;
using System.IO;
namespace Downloader
{
public class Data
{
private static string directory = Directory.GetCurrentDirectory();
private readonly static string defaultJsonFile = directory + #"\clips.json";
private readonly static string defaultOutputPath = directory + #"\Clips\";
private readonly static string clipsLink = "https://api.twitch.tv/helix/clips?";
public string OutputPath { get; set; }
public string JsonFile { get; set; }
public string ClientID { get; private set; }
public string Authentication { get; private set; }
public string QueryURL { get; private set; }
public Data()
{
OutputPath = defaultOutputPath;
JsonFile = defaultJsonFile;
}
public Data(string clientID, string authentication)
{
ClientID = clientID;
Authentication = authentication;
OutputPath = defaultOutputPath;
JsonFile = defaultJsonFile;
}
public Data(string clientID, string authentication, string outputPath)
{
ClientID = clientID;
Authentication = authentication;
OutputPath = directory + #"\" + outputPath + #"\";
JsonFile = OutputPath + outputPath + ".json";
}
public void GetQuery()
{
Console.Write("Please enter your query: ");
QueryURL = clipsLink + Console.ReadLine();
}
public void GetClientID()
{
Console.WriteLine("Enter your client ID");
ClientID = Console.ReadLine();
}
public void GetAuthentication()
{
Console.WriteLine("Enter your Authentication");
Authentication = Console.ReadLine();
}
public void OutputFolderExists()
{
if (!Directory.Exists(OutputPath))
{
Directory.CreateDirectory(OutputPath);
}
}
}
}
JsonGenerator.cs
using System;
using System.IO;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Linq;
namespace Downloader
{
public static class JsonGenerator
{
// This class has no constructor.
// You call the Generate methods, passing in all required data.
// The file will then be generated.
private static Data data;
public static async Task Generate(Data clientData)
{
data = clientData;
string responseContent = null;
// Loop that runs until the api request goes through
bool authError = true;
while (authError)
{
authError = false;
try
{
responseContent = await GetHttpResponse();
}
catch (HttpRequestException)
{
Console.WriteLine("Invalid authentication, please enter client-ID and authentication again!");
data.GetClientID();
data.GetAuthentication();
authError = true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
authError = true;
}
}
data.OutputFolderExists();
GenerateJson(responseContent);
}
// Returns the contents of the resopnse to the api call as a string
private static async Task<string> GetHttpResponse()
{
// Creating client
HttpClient client = new HttpClient();
if (data.QueryURL == null)
{
data.GetQuery();
}
// Setting up request
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, data.QueryURL);
// Adding Headers to request
requestMessage.Headers.Add("client-id", data.ClientID);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", data.Authentication);
// Receiving response to the request
HttpResponseMessage responseMessage = await client.SendAsync(requestMessage);
// Gets the content of the response as a string
string responseContent = await responseMessage.Content.ReadAsStringAsync();
return responseContent;
}
// Generates or adds to the .json file that contains data on each clip
private static void GenerateJson(string responseContent)
{
// Parses the data from the response to the api request
Root responseResult = JsonConvert.DeserializeObject<Root>(responseContent);
// If the file doesn't exist, we need to create it and add a '[' at the start
if (!File.Exists(data.JsonFile))
{
FileStream file = File.Create(data.JsonFile);
file.Close();
// The array of json objects needs to be wrapped inside []
File.AppendAllText(data.JsonFile, "[\n");
}
else
{
// For a pre-existing .json file, The last object won't have a comma at the
// end of it so we need to add it now, before we add more objects
string[] jsonLines = File.ReadAllLines(data.JsonFile);
File.WriteAllLines(data.JsonFile, jsonLines.Take(jsonLines.Length - 1).ToArray());
File.AppendAllText(data.JsonFile, ",");
}
// If the file already exists, but there was no [ at the start for whatever reason,
// we need to add it
if (File.ReadAllText(data.JsonFile).Length == 0 || File.ReadAllText(data.JsonFile)[0] != '[')
{
File.WriteAllText(data.JsonFile, "[\n" + File.ReadAllText(data.JsonFile));
}
string json;
// Loops through each ClipInfo object that the api returned
for (int i = 0; i < responseResult.data.Count; i++)
{
// Serializes the ClipInfo object into a json style string
json = JsonConvert.SerializeObject(responseResult.data[i]);
// Adds the serialized contents of ClipInfo to the .json file
File.AppendAllText(data.JsonFile, json);
if (i != responseResult.data.Count - 1)
{
// All objects except the last require a comma at the end of the
// object in order to correctly format the array of json objects
File.AppendAllText(data.JsonFile, ",");
}
// Adds new line after object entry
File.AppendAllText(data.JsonFile, "\n");
}
// Adds the ] at the end of the file to close off the json objects array
File.AppendAllText(data.JsonFile, "]");
}
}
}
FileDownloader.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace Downloader
{
public class FileDownloader
{
private static Data data;
private static List<Task> tasks;
public async static void DownloadAllFiles(Data clientData)
{
data = clientData;
data.OutputFolderExists();
// Deserialize .json file and get ClipInfo list
List<ClipInfo> clips = JsonConvert.DeserializeObject<List<ClipInfo>>(File.ReadAllText(data.JsonFile));
tasks = new List<Task>();
foreach (ClipInfo clip in clips)
{
tasks.Add(DownloadFilesAsync(clip));
}
await Task.WhenAll(tasks);
}
private static void GetData()
{
if (data.ClientID == null)
{
data.GetClientID();
}
if (data.Authentication == null)
{
data.GetAuthentication();
}
if (data.QueryURL == null)
{
data.GetQuery();
}
}
private static string GetClipURL(ClipInfo clip)
{
// Example thumbnail URL:
// https://clips-media-assets2.twitch.tv/AT-cm%7C902106752-preview-480x272.jpg
// You can get the URL of the location of clip.mp4
// by removing the -preview.... from the thumbnail url */
string url = clip.thumbnail_url;
url = url.Substring(0, url.IndexOf("-preview")) + ".mp4";
return url;
}
private async static Task DownloadFilesAsync(ClipInfo clip)
{
WebClient client = new WebClient();
string url = GetClipURL(clip);
string filepath = data.OutputPath + clip.id + ".mp4";
await client.DownloadFileTaskAsync(new Uri(url), filepath);
}
private static void FileDownloadComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
tasks.Remove((Task)sender);
}
}
}
Program.cs
using System;
using System.Threading.Tasks;
using Downloader;
namespace ClipDownloader
{
class Program
{
private static string clientID = "{your_client_id}";
private static string authentication = "{your_authentication}";
async static Task Main(string[] args)
{
Console.WriteLine("Enter your output path");
string outputPath = Console.ReadLine();
Data data = new Data(clientID, authentication, outputPath);
Console.WriteLine(data.OutputPath);
//await JsonGenerator.Generate(data);
FileDownloader.DownloadAllFiles(data);
}
}
}
The example query I usually type in is "game_id=510218"
async void is your problem
Change
public static async void DownloadAllFiles(Data clientData)
To
public static async Task DownloadAllFiles(Data clientData)
Then you can await it
await FileDownloader.DownloadAllFiles(data);
The longer story:
async void runs unobserved (fire and forget). You can't wait for them to finish. In essence as soon as your program starts the task, it finishes, and tears down the App Domain and all your sub tasks, leading you to believe nothing is working.
I'm trying to stay on topic here as best as I can, but when using JsonConvert.DeserializeObject{T}, isn't T suppose to be an encapsulating root object type? I have never used it the way you're using it, so I'm just curious if that might be your bug. I could be completely wrong, and spare me if i am, but JSON is key:value based. Deserializing directly to a List doesn't really make sense. Unless there is a special case in the deserializer? List would be a file that's purely an array of ClipInfo values being deserialized into the members of List{T}(private T[] _items, private int _size, etc.) It needs a parent root object.
// current JSON file format implication(which i dont think is valid JSON?(correct me please)
clips:
[
// clip 1
{ "id": "", "url": "" },
// clip N
{ "id": "", "url": "" },
]
// correct(?) JSON file format
{ // { } is the outer encasing object
clips:
[
// clip 1
{ "id": "", "url": "" },
// clip N
{ "id": "", "url": "" },
]
}
class ClipInfoJSONFile
{
public List<ClipInfo> Info { get; set; }
}
var clipInfoList = JsonConverter.DeserializeObject<ClipInfoJSONFile>(...);
I have to update a project using Lucene.NET. It first time I meet this library, and I should update the references to a new version. So I did with Lucene references via a NuGet.
But actually I should in a way update some methods that disappeared in the new versions.
public abstract class AnalyzerView
{
public abstract string Name { get; }
public virtual string GetView(TokenStream tokenStream,out int numberOfTokens)
{
StringBuilder sb = new StringBuilder();
Token token = tokenStream.Next();
numberOfTokens = 0;
while (token != null)
{
numberOfTokens++;
sb.Append(GetTokenView(token));
token = tokenStream.Next();
}
return sb.ToString();
}
protected abstract string GetTokenView(Token token);
}
The documentation is not very clear for me. As I understood I should use something like
while (tokenStream.IncrementToken()) { ... }
but how to obtain that following token is a mystery for me.
I saw similar question on StackOverflow, but my problem is that I need to obtain a Token rather thatn a string, because I have some code that uses tokens, like this one:
public class TermWithOffsetsView : AnalyzerView {
public override string Name {
get { return "Terms With Offsets"; }
}
protected override string GetTokenView(Token token) {
return token.TermText() +
" Start: " + token.StartOffset().ToString().PadLeft(5) +
" End: " + token.EndOffset().ToString().PadLeft(5) +
"\r\n";
}
}
Finally, after some researches, implemented something like this:
public abstract class AnalyzerView
{
public abstract string Name { get; }
public virtual string GetView(TokenStream tokenStream,out int numberOfTokens)
{
StringBuilder sb = new StringBuilder();
numberOfTokens = 0;
while (tokenStream.IncrementToken())
{
numberOfTokens++;
sb.Append(GetTokenView(tokenStream));
}
return sb.ToString();
}
protected abstract string GetTokenView(TokenStream tokenStream);
}
with the derived class like this:
public class TermWithOffsetsView : AnalyzerView {
public override string Name {
get { return "Terms With Offsets"; }
}
protected override string GetTokenView(TokenStream tokenStream) {
ITermAttribute termAtt = tokenStream.AddAttribute<ITermAttribute>();
IOffsetAttribute offsetAtt=tokenStream.AddAttribute<IOffsetAttribute>();
return string.Format("{0} Start: {1} End: {2}{3}",
termAtt.Term,
offsetAtt.StartOffset.ToString().PadLeft(5),
offsetAtt.EndOffset.ToString().PadLeft(5),
Environment.NewLine);
}
}
I have a Neo4j Graphdatabase with access via the Neo4jClient. (It is a .NET client for the REST api of Neo4j)
There is the beginning of a documentation.
What I have done
The connection to the database works.
Client = new GraphClient(new Uri("http://localhost:7474/db/data"));
Client.Connect();
This way I can insert Nodes...
Client.Create(new myNodeClass { name = "Nobody" });
... and query them.
Node<myNodeClass> Node = Client.Get<WordNode>(138);
return Node.Data.name;
What I want to do
I simply want to add and update relationships between Nodes. (The type of relationship have to be numeric.)
Unfortunately there is no documentation about relationships yet.
There is a command named CreateRelationship. But I can't get it work.
Client.CreateRelationship(Neo4jClient.NodeReference<TSourceNode>, TRelationship);
Can you give me an example of adding and updating (numeric) relationships?
There's a lot to be found in the test cases... Such as this:
http://hg.readify.net/neo4jclient/src/4693da483a90/Test/ApiUsageIdeas.cs
I was stuck too then I realized I needed to specify the type parameter of the source node reference parameter in the CreateRelationship method.
In this example, I have created the relationship. I have not yet updated the relationship.
Disclosure(It works on my machine as a console application running visual studio 2012, YMMV)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using Neo4jClient;
namespace Neo4jClientExample
{
class MyConsoleProgram
{
private GraphClient Client {get;set; }
static void Main(string[] args)
{
try{
GraphClient client = new GraphClient(new Uri("http://localhost:7474/db/data"));
client.Connect();
Us us = new Us { Name = "We are Us" };
NodeReference<Us> usRef = client.Create(us);
Console.WriteLine("us node.id: {0}", usRef.Id);
var queryUs = client.Cypher.Start("n", "node(" + usRef.Id + ")").Return<Node<Us>>("n");
Console.WriteLine("Us node name: {0}\n", queryUs.Results.AsEnumerable<Node<Us>>().First().Data);
AllYourBase allYourBase = new AllYourBase { Name = "We are all your base" };
NodeReference<AllYourBase> allYourBaseRef = client.Create(allYourBase);
Console.WriteLine("AllYourBase node.id: {0}",allYourBaseRef.Id);
var queryAllYourBase = client.Cypher.Start("n", "node(" + allYourBaseRef.Id + ")").Return<Node<AllYourBase>>("n");
Console.WriteLine("AllYourBase node name: {0}\n", queryAllYourBase.Results.AsEnumerable<Node<AllYourBase>>().First().Data);
RelationshipReference areBelongToRef = client.CreateRelationship(allYourBaseRef, new AreBelongTo(usRef));
var query = client.Cypher.Start("allyourbase", "node(" + allYourBaseRef.Id + ")").Match("allyourbase-[:ARE_BELONG_TO]->us").Return<Node<AllYourBase>>("allyourbase");
query.ExecuteWithoutResults();
Console.WriteLine("Result of querying for all your base that belongs to us: {0}", query.Results.AsEnumerable<Node<AllYourBase>>().First().Data.Name);
}
catch(Exception ex)
{
Console.WriteLine("{0}", ex.Message);
Console.WriteLine("{0}", ex.InnerException);
}
Console.ReadKey();
}
}
public class Us
{
public string Name {get; set;}
public Us()
{
}
}
public class AllYourBase
{
public string Name { get; set; }
public AllYourBase()
{
}
}
public class AreBelongTo : Relationship, IRelationshipAllowingSourceNode<AllYourBase>,
IRelationshipAllowingTargetNode<Us>
{
public AreBelongTo(NodeReference targetNode)
: base(targetNode)
{}
public const string TypeKey = "ARE_BELONG_TO";
public override string RelationshipTypeKey
{
get { return TypeKey; }
}
}
you could have a look at the tests, http://hg.readify.net/neo4jclient/src/4693da483a90/Test/RelationshipTests.cs or contact the author on the Neo4j mailing list, groups.google.com/group/neo4j ?