我写了一个程序,做了以下几件事:
我以前从未在C#中使用过网络,所以可能在我的代码中犯了一些错误(或者它的某些部分可能不可靠)。这就是我发这个的原因。
我的目标是JSON4.0,并希望避免使用第三方外部库与远程主机通信、反序列化.NET文档等。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
namespace ConsoleApplication16
{
[DataContract]
class acoustid_mbids
{
[DataContract]
public class result{
[DataMember]
public double score { get; set; }
[DataMember]
public string id { get; set; }
[DataMember]
public recording[] recordings { get; set; }
}
[DataContract]
public class recording
{
[DataMember]
public string id { get; set; }
}
[DataMember]
public string status { get; set; }
[DataMember]
public result[] results { get; set; }
}
[DataContract]
class recording
{
[DataMember]
public string title { get; set; }
[DataMember]
public string length { get; set; }
[DataMember(Name = "artist-credit")]
public artist[] artists { get; set; }
[DataMember]
public genre[] genres { get; set; }
[DataMember]
public release[] releases { get; set; }
[DataContract]
public class artist
{
[DataMember]
public string name;
[DataMember]
public string joinphrase;
}
[DataContract]
public class genre
{
[DataMember]
public int count;
[DataMember]
public string name;
}
[DataContract]
public class release
{
[DataMember]
public string title;
[DataMember]
public string date;
[DataMember]
public string id; //required for fetching artwork
}
}
class Program
{
public static List<recording> avail_recordings = new List<recording>();
public static List<string> fpcalc_output = new List<string>();
public const string API_KEY="xxxxxxx";
public static HttpWebRequest request;
public static HttpWebResponse response;
static void Main(string[] args)
{
DataContractJsonSerializer parseJson;
using (Process proc = new Process())
{
proc.StartInfo.FileName = "fpcalc.exe";
proc.StartInfo.Arguments = " Kalimba.mp3";
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072;
request = (HttpWebRequest)HttpWebRequest.Create("http://api.acoustid.org/v2/lookup?client="+API_KEY+"&duration="+fpcalc_output[0].Replace("DURATION=",String.Empty)+"&fingerprint="+fpcalc_output[1].Replace("FINGERPRINT=",String.Empty)+"&meta=recordingids");
request.Method = "GET";
response = (HttpWebResponse)request.GetResponse();
parseJson = new DataContractJsonSerializer(typeof(acoustid_mbids));
acoustid_mbids acoustid_session = (acoustid_mbids)parseJson.ReadObject(response.GetResponseStream());
parseJson = new DataContractJsonSerializer(typeof(recording));
response.Close();
response = null;
for (int i = 0; i < acoustid_session.results.Length; i++)
{
for (int j = 0; j < acoustid_session.results[i].recordings.Length; j++)
{
request = (HttpWebRequest)HttpWebRequest.Create("http://musicbrainz.org/ws/2/recording/" + acoustid_session.results[i].recordings[j].id + "?fmt=json&inc=artist-credits+releases+genres");
request.KeepAlive = false;
request.Method = "GET";
request.UserAgent = "SimpleID3Editor/1.0 ( maxvoloshin71@mail.ru )";
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
Console.WriteLine((int)((HttpWebResponse)ex.Response).StatusCode);
break;
}
if (response != null)
{
avail_recordings.Add((recording)parseJson.ReadObject(response.GetResponseStream()));
response.Close();
}
}
}
Console.ReadKey();
}
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Called!");
fpcalc_output.Add(e.Data);
}
}
}发布于 2021-02-08 14:17:22
以下是我的观察:
acoustid_mbids \ recording:一般的指导方针是在类名上使用Pascal大小写。AcoustidMbids和Recording将是建议的名称。DataMember:当您指定它的Name属性时,这个属性也会非常有用。[DataContract(Name = "acoustid_mbids")]
class AcoustidMbids
{
[DataContract(Name = "result")]
public class Result
{
[DataMember(Name ="score" )]
public double Score { get; set; }
[DataMember(Name = "id")]
public string Id { get; set; }
[DataMember(Name = "recordings")]
public Recording[] Recordings { get; set; }
}
...
}Main:请尽量避免将所有内容都放入Main方法中。static void Main(string[] args)
{
List<string> fpcalc_output = GetMetaFromMP3("Kalimba.mp3");
AcoustidMbids acoustid_session = GetMetaFromAcoustid(fpcalc_output);
List<Recording> avail_recordings = GetMetaFromMusicbrainz(acoustid_session);
}static HttpWebRequest request:请尽量避免重用HttpWebRequest和HttpWebResponse对象。GetMetaFromAcoustid和GetMetaFromMusicbrainz)都应该处理它们自己的实例。proc.StartInfo.FileName = "fpcalc.exe";:你可以独立进程及其ProcessStartInfo设置。var processInfo = new ProcessStartInfo
{
FileName = "fpcalc.exe",
Arguments = " Kalimba.mp3",
RedirectStandardOutput = true,
UseShellExecute = false,
};
using (Process proc = Process.Start(processInfo))
{
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
proc.BeginOutputReadLine();
proc.WaitForExit();
}new DataReceivedEventHandler(proc_OutputDataReceived):您可以使用Lambda表达式创建匿名委托:proc.OutputDataReceived += (s, e) =>
{
Console.WriteLine("Called!");
fpcalc_output.Add(e.Data);
};(SecurityProtocolType)3072:请尽量避免使用神奇的数字,而使用常量。const int Tls12 = 3072;
...
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)Tls12;request = (HttpWebRequest)HttpWebRequest.Create(:如前所述,请为每个调用尝试使用单独的实例。GET是默认方法,因此不必指定:var request = (HttpWebRequest)WebRequest.Create(url);"&duration=" + fpcalc_output[0].Replace("DURATION=", String.Empty):var duration = fpcalc_output[0].Replace("DURATION=", string.Empty);
var fingerprint = fpcalc_output[1].Replace("FINGERPRINT=", string.Empty);
var url = "http://api.acoustid.org/v2/lookup?client=" + API_KEY + "&duration=" + duration + "&fingerprint=" + fingerprint + "&meta=recordingids";string.Empty而不是String.Empty。请阅读此undefined以更好地理解差异。fpcalc_output[1]可以抛出OutOfRangeException。string durationKey = "DURATION="
int durationIdx = fpcalc_output.FindIndex(a => a.Contains(durationKey));
if(durationIdx == -1) throw new InvalidOperationException("Duration is missing from the fpcalc result");
fpcalc_output[durationIdx].Replace(durationKey, string.Empty);System.Web.HttpUtility.ParseQueryString(相关SO主题)。response = (HttpWebResponse)request.GetResponse():在执行任何进一步的操作之前,请检查响应的StatusCode。response = (HttpWebResponse)request.GetResponse();
if(response.StatusCode != HttpStatusCode.OK)
throw new InvalidOperationException("acoustid did not respond in the expected way.");response.GetResponseStream():请记住,这里使用的是流。如果不需要的话,就应该处理掉。相关SO主题parseJson.ReadObject:如果服务响应与预期结构不同,这会引发SerializationException。为这种情况做好准备,使您的解决方案更加健壮。for (int i = 0; i < acoustid_session.results.Length; i++):优先于foreach循环(这可以极大地提高可读性:foreach (var result in acoustid_session.results)
foreach (var record in result.Recordings)
{
...
}response.Close():如前所述,与显式调用Close相比,请更喜欢使用。发布于 2021-02-08 14:20:58
一些简短的评论:
avail_recordings和fpcalc_output不遵循微软的指导原则(例如,不要使用"snake case",不要不必要地缩写,.)。request = (HttpWebRequest)HttpWebRequest.Create("http://api.acoustid.org/v2/lookup?client="+API_KEY+"&duration="+fpcalc_output[0].Replace("DURATION=",String.Empty)+"&fingerprint="+fpcalc_output[1].Replace("FINGERPRINT=",String.Empty)+"&meta=recordingids");几乎是不可能阅读的。考虑使用类似于new List<KeyValuePair<string, string>>的内容,并将查询字符串的每个键/值对存储为KeyValuePair<string, string>,然后使用.Select(x => string.Format("{0}={1}", x.Key, x.Value))或使用NameValueCollection从该集合编译查询字符串。fpcalc,另一个方法调用acoustid.org,另一个方法调用musicbrainz.org,等等。i和j,为什么不使用foreach呢?https://codereview.stackexchange.com/questions/255756
复制相似问题