Doxygen and add a value of an attribute to the output documentation - c#

ServiceStack marks rest paths for web services using c# attributes.
For example
[RestService("/hello1")]
[RestService("/hello2")]
public class Hello
I would like to make Doxygen include values of the RestService attribute in the doxygen output for the Hello class. I'm not concerned too much with pretty formattin if the full line with brackets is included in the output document.
Any suggestions?
A quick and dirty trick would be a preferable to writing a Doxygen extension ;)
Cheers
Tymek
====EDIT
The Python version (so will work on Windows easily) of doxygen user's answer would be:
#!/usr/bin/env python
import sys
import re
if (len(sys.argv) < 2):
print "No input file"
else:
f = open(sys.argv[1])
line = f.readline()
while line:
re1 = re.compile("\[RestService\(\"(.*)\",.*\"(.*)\"\)]")
re1.search(line)
sys.stdout.write(re1.sub(r"/** \\b RestService: \2 \1\\n */\n", line))
#sys.stdout.write(line)
line = f.readline()
f.close()
and the DOXYFILE would have:
INPUT_FILTER = "doxygenFilter.py"

You could make an input filter that converts a line with
[RestService("/hello1")]
to
/** \b RestService: "/hello1"\n */
like for instance by putting following piece of perl magic in a file called filter.pl:
open(F, "<", $ARGV[0]);
while(<F>) { /^\s*\[RestService\((.*)\)\]\s*$/ ?
print "/** \\b RestService: $1\\n */\n" : print $_; }
and use that with the INPUT_FILTER tag in the Doxyfile:
INPUT_FILTER = "perl filter.pl"

Instead of using a python or perl scrip, it made more sense to me to do it in C#
As an added bonus inline xml documentation for attributes will also be added to the documentation.
Example:
[FromForm(Name = "e_mail")]
[Required] /// <div>Specifies that a data field value is required.</div><p>More info...</p>
Name the C# console project "AttributesDocumenter" and use the resulting binary with the INPUT_FILTER tag in the Doxyfile:
INPUT_FILTER = "AttributesDocumenter.exe"
using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace AttributesDocumenter
{
class Program
{
static async Task Main(string[] args)
{
if (args.Length < 1)
{
await Console.Out.WriteLineAsync("No input file");
return;
}
var f = File.OpenText(args[0]);
while (!f.EndOfStream)
{
var line = await f.ReadLineAsync();
var match = Regex.Match(line, #"\s*\[(.*)]\s*");
if (match.Success)
{
var inlineXmlComment = Regex.Match(line, #".*\/\/\/");
if (inlineXmlComment.Success)
{
var inlineXmlCommentList = new Regex(#"\s*(</?([^>/]*)/?>).*").Matches(line);
var inlineXmlCommentCombined = string.Join("", inlineXmlCommentList);
await Console.Out.WriteLineAsync($"{inlineXmlComment.Value} <para><b>Attribute:</b> {match.Value}</para> {inlineXmlCommentCombined}");
}
else
{
await Console.Out.WriteLineAsync($"{line} /// <para><b>Attribute:</b> {match.Value}</para>");
}
}
else
{
await Console.Out.WriteLineAsync(line);
}
}
}
}
}

Related

Can I use WebUtility.HtmlDecode to decode XML?

I have an XML-encoded attribute value. This is actually from a processing instruction. So the original data looks something like this:
<root><?pi key="value" data="<foo attr="bar">Hello world</foo>" ?></root>
I can parse it like this:
using System;
using System.Linq;
using System.Xml.Linq;
public class Program
{
private const string RawData = #"<root><?pi key=""value"" data=""<foo attr="bar">Hello world</foo>"" ?></root>";
public static void Main()
{
XDocument doc = GetXDocumentFromProcessingInstruction();
IEnumerable<XElement> fooElements = doc.Descendants("foo");
// ...
}
private static XProcessingInstruction LoadProcessingInstruction()
{
XDocument doc = XDocument.Parse(rawData);
return doc
.DescendantNodes()
.OfType<XProcessingInstruction>()
.First();
}
private static XDocument GetXDocumentFromProcessingInstruction()
{
XProcessingInstruction processingInstruction = LoadProcessingInstruction();
// QUESTION:
// Can there ever be a situation where HtmlDecode wouldn't decode the XML correctly?
string decodedXml = WebUtility.HtmlDecode(processingInstruction.Data);
// This works well, but it contains the attributes of the processing
// instruction as text.
string dummyXml = $"<dummy>{xml}</dummy>";
return XDocument.Parse(dummyXml);
}
This works absolutely fine, as far as I can tell.
But I am wondering if there might be some edge cases where it may fail, because of differences in how data would be encoded in XML vs. HTML.
Anybody have some more insight?
Edit:
Sorry, I made some incorrect assumptions about XProcessingInstruction.Data, but the code above was still working fine, so my question stands.
I have nonetheless rewritten my code and wrapped everything in an XElement, which (of course) removed the issue altogether:
private static XDocument GetXDocumentFromProcessingInstruction2()
{
XProcessingInstruction processingInstruction = LoadProcessingInstruction();
string encodedXml = string.Format("<dummy {0} />", processingInstruction.Data);
XElement element = XElement.Parse(encodedXml);
string parsedXml = element.Attribute("data").Value;
return XDocument.Parse(parsedXml);
}
So this does exactly what I need. But since WebUtility.HtmlDecode worked sufficiently well, I would still like to know if there could have been a situation where the first approach could have failed.
Removing the question marks and adding a forward slash at end of your input I got this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string input = "<pi data=\"<foo attr="bar">Hello world</foo>\" />";
XElement pi = XElement.Parse(input);
string data = (string)pi.Attribute("data");
XElement foo = XElement.Parse(data);
string attr = (string)foo.Attribute("attr");
string innertext = (string)foo;
}
}
}

Parsing Json information from a Json file as a string

I am looking for some help with regards to Parsing the the value "mppdemo" in the below json file (See screenshot)
{
"client":{
"isWebLogin":false,
"registryName": "mpdemo",
"walletCode": "Local"
}
}
I have done some research in and arround the webs but alot of the examples wither are out dated or dont work.
This is what i have tried
//JObject T = JObject.Parse(File.ReadAllText(DownloadConfigFilelocation));
var source = File.ReadAllText(DownloadConfigFilelocation);
var JavaScriptSerializer MySerializer = new JavaScriptSerializer();
var myObj = MySerializer.Deserialize<T>(source);
var RegistryName = myObj.searchResults[0].hotelID;
MessageBox.Show(RegistryName);
The above doesnt pick up the JavaScriptSerializer function from the library even though im using the using System.Web.Script.Serialization;
Can someone help me get this code segment to work
I hope i have provided enough info
EDIT: I just realized that you're having another problem - that your compiler does not recognize the System.Web.Script.Serialization.JavaScriptSerializer type. You'll need to add a reference to System.Web.Extensions.dll to your project. I don't know what IDE you are using, but for example in SharpDevelop you can right click References > Add Reference > in filter start typing "System.Web.Extensions" > among results find "System.Web.Extensions" and double click it (it will be moved to lower window) > hit OK and compile your project.
If you still want to use System.Web.Script.Serialization.JavaScriptSerializer, I'd probably do it like this:
using System;
using System.Text.RegularExpressions;
using System.Web.Script.Serialization;
namespace jsonhratky
{
public static class Program {
public static void Main(string[] args)
{
var instance = new JsonParsingTest();
}
}
public class JsonParsingTest
{
class Response {
public Client client;
}
class Client {
public bool isWebLogin;
public string registryName;
public string walletCode;
}
const string JSON_EXAMPLE = ("{" + ("\"client\":{" + ("\"isWebLogin\":false," + ("\"registryName\": \"mpdemo\"," + ("\"walletCode\": \"Local\"" + ("}" + "}"))))));
public JsonParsingTest() {
// Solution #1 using JavaScriptSerializer
var serializer = new JavaScriptSerializer();
Response parsed = serializer.Deserialize<Response>(JSON_EXAMPLE);
Console.WriteLine("parsed isWebLogin: " + parsed.client.isWebLogin);
Console.WriteLine("parsed registryName: " + parsed.client.registryName);
Console.WriteLine("parsed walletCode: " + parsed.client.walletCode);
// Solution #2 (not recommended)
var matches = Regex.Match(JSON_EXAMPLE, "registryName\":.*?\"([^\"]+)\"", RegexOptions.Multiline);
if (matches.Success) {
Console.WriteLine("registryName parsed using Regex: " + matches.Groups[1].Value);
} else {
Console.WriteLine("Solution using Regex failed.");
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
You need to create a "POJO" class (there's probably another term in C# for plain old classes) with fields matching those in your string response. Since your fields isWebLogin, registryName and walletCode are not directly part of main object (Response) but they belong to sub-class (Client), you need two classes: Response (or call it whatever you want) and then the field "client" must match string in response (as well as the fields of the sub-class).
Result:
Anyway, I also included a solution using Regex, but I absolutely don't recommend that. It's suitable only as a workaround and only then if you know that your response will never contain more than one "client" objects.
The problem seems to be in this line of your code var myObj = MySerializer.Deserialize<T>(source); You need to give the type of object instead of T.

Getting a SemanticModel of a cshtml file?

I'd like to use Roslyn to analyze semantic information within the context of a block of C# code inside a Razor View.
Is there any way (within Visual Studio 2015, or even in a unit test) to get the SemanticModel that represents this code?
Razor files contain a C# projection buffer with the generated C# code (including the parts that you don't write yourself). This buffer has full Roslyn services and is exactly what you're looking for.
You need to walk through the TextView's BufferGraph and find the CSharp buffer; you can then get its Document and semantic model.
If you're starting from the cursor location, you need simply need to map that location to a CSharp buffer.
Note that it is perfectly legal for a TextView to contain multiple CSharp buffers. (although the Razor editor will never do that)
If you aren't working in a TextView, you need to do all of this yourself; you need to run the Razor source through the Razor compiler to get the generated C# source, then compile that with Roslyn to get a semantic model.
Extract the code representing the view from the Razor view file using RazorTemplateEngine.GenerateCode and CSharpCodeProvider.GenerateCodeFromCompileUnit (or the VBCodeProvider if you want the intermediate source as VB.NET). You can then use Roslyn to parse the code.
There's an example of using Roslyn with Razor view files here.
Take note that GenerateCode carries a caveat:
This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.
Just in case anyone else gets stuck on this, I have mini sample app which may help.
I had a CMS class like this:
public partial class CMS
{
public static string SomeKey
{
get { return (string) ResourceProvider.GetResource("some_key"); }
}
// ... and many more ...
}
... and I wanted to find out which of these were used throughout my solution for a report ... Enter Roslyn!
The following app will print out the count for the used and unused references:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Razor;
namespace TranslationSniffer
{
class Program
{
static void Main(string[] args)
{
new Program().Go().Wait();
}
public async Task Go()
{
// Roslyn!
var ws = MSBuildWorkspace.Create();
// Store the translation keys...
List<string> used = new List<string>();
List<string> delete = new List<string>();
string solutionRoot = #"C:\_Code\PathToProject\";
string sln = solutionRoot + "MySolution.sln";
// Load the solution, and find all the cshtml Razor views...
var solution = await ws.OpenSolutionAsync(sln);
var mainProj = solution.Projects.Where(x => x.Name == "ConsumerWeb").Single();
FileInfo[] cshtmls = new DirectoryInfo(solutionRoot).GetFiles("*.cshtml", SearchOption.AllDirectories);
// Go through each Razor View - generate the equivalent CS and add to the project for compilation.
var host = new RazorEngineHost(RazorCodeLanguage.Languages["cshtml"]);
var razor = new RazorTemplateEngine(host);
var cs = new CSharpCodeProvider();
var csOptions = new CodeGeneratorOptions();
foreach (var cshtml in cshtmls)
{
using (StreamReader re = new StreamReader(cshtml.FullName))
{
try
{
// Let Razor do it's thang...
var compileUnit = razor.GenerateCode(re).GeneratedCode;
// Pull the code into a stringbuilder, and append to the main project:
StringBuilder sb = new StringBuilder();
using (StringWriter rw = new StringWriter(sb))
{
cs.GenerateCodeFromCompileUnit(compileUnit, rw, csOptions);
}
// Get the new immutable project
var doc = mainProj.AddDocument(cshtml.Name + ".cs", sb.ToString());
mainProj = doc.Project;
}
catch(Exception ex)
{
Console.WriteLine("Compile fail for: {0}", cshtml.Name);
// throw;
}
continue;
}
}
// We now have a new immutable solution, as we have changed the project instance...
solution = mainProj.Solution;
// Pull out our application translation list (its in a static class called 'CMS'):
var mainCompile = await mainProj.GetCompilationAsync();
var mainModel = mainCompile.GetTypeByMetadataName("Resources.CMS");
var translations = mainModel.GetMembers().Where(x => x.Kind == SymbolKind.Property).ToList();
foreach (var translation in translations)
{
var references = await SymbolFinder.FindReferencesAsync(translation, solution) ;
if (!references.First().Locations.Any())
{
Console.WriteLine("{0} translation is not used!", translation.Name);
delete.Add(translation.Name);
}
else
{
Console.WriteLine("{0} :in: {1}", translation.Name, references.First().Locations.First().Document.Name);
used.Add(translation.Name);
}
}
Console.WriteLine();
Console.WriteLine("Used references {0}. Unused references: {1}", used.Count, delete.Count);
return;
}
}
}
Roslyn only models cshtml files while they are open, but during that time they are similar to every other source file in the Workspace model.
Is there something specific you have tried that isn't working?

c# add new namespace to project

How can I add a namespace to a c# project? I am a beginner.
if(!string.IsNullOrEmpty(result))
{
CoderBuddy.ExtractEmails helper = new CoderBuddy.ExtractEmails(result);
EmailsList = helper.Extract_Emails;
}
My Form1 needs to use the namespace below:
// this is the file that I need to add
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace Coderbuddy
{
public class ExtractEmails
{
private string s;
public ExtractEmails(string Text2Scrape)
{
this.s = Text2Scrape;
}
public string[] Extract_Emails()
{
string[] Email_List = new string[0];
Regex r = new Regex(#"[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,6}", RegexOptions.IgnoreCase);
Match m;
//Searching for the text that matches the above regular expression(which only matches email addresses)
for (m = r.Match(s); m.Success; m = m.NextMatch())
{
//This section here demonstartes Dynamic arrays
if (m.Value.Length > 0)
{
//Resize the array Email_List by incrementing it by 1, to save the next result
Array.Resize(ref Email_List, Email_List.Length + 1);
Email_List[Email_List.Length - 1] = m.Value;
}
}
return Email_List;
}
}
}
Well, add a using statement in your .cs page
using Coderbuddy;
Then your code can access the methods exposed by this type.
OR, put your winform .cs file in the same namespace (not a recommended idea)
Put this at the top of your code-behind file:
using Coderbuddy;
Read this introduction to namespaces and assemblies on MSDN.
(I am assuming you need to add that second file to your own project. If it is already part of another project in your solution, then add it as a project reference as Darkhydro has answered.)
You don't need to explicitly add namespaces to your project. The namespace declaration in line 6 of the file that you need to use does it implicity.
For this example, add a blank file called ExtractEmails.cs to your project (the convention if a file contains only one class definition is to name the file after the class), and then paste that code into it. Boom - namespace added :)
In your form code, you are already using the fully qualified name of the class (that is, you are mentioning the namespace in the line
CoderBuddy.ExtractEmails helper = new CoderBuddy.ExtractEmails(result);
so you don't need a "using" statement.
If you did add "using CoderBuddy;" to the top of your form's .cs file, then that line could change to
ExtractEmails helper = new ExtractEmails(result);
But in this case I would leave it as you already have it, because the namespace hints at the fact that the ExtractEmails code is slightly separated from the rest of your code.

C# write multi lines to cs file

I googled and found the solution at MSDN.
// Compose a string that consists of three lines.
string lines = "First line.\r\nSecond line.\r\nThird line.";
// Write the string to a file.
System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test.txt");
file.WriteLine(lines);
file.Close();
How to extend the lines to complex content which including some natural C# code lines.
eg. I want to write the information below to my test.cs file.
Why?
I am parsing a XML schema with C# Console Application. And i want to generate the Console Result to a .cs file during the compiler time.
using System;
using System.Collections.Generic;
using System.Text;
namespace CommonDef
{
public class CCODEData
{
public int iCodeId;
public string sCode;
public CODEDType cType;
public int iOccures;
}
[Description("CodeType for XML schema.")]
public enum CODEDType
{
cString = 1,
cInt = 2,
cBoolean = 3,
}
thank you.
If your source code is hardcoded as in your sample, you could use a C# literal string:
string lines =
#"using System;
using System.Collections.Generic;
using System.Text;
namespace CommonDef
..."
Anyway in such cases it is a better idea (more readable and maintainable) to have the whole text contents into a text file as an embedded resource in your assembly, then read it using GetManifestResourceStream.
(I'm assuming you're trying to build up the result programmatically - if you genuinely have hard-coded data, you could use Konamiman's approach; I agree that using an embedded resource file would be better than a huge verbatim string literal.)
In your case I would suggest not trying to build up the whole file into a single string. Instead, use WriteLine repeatedly:
using (TextWriter writer = File.CreateText("foo.cs"))
{
foreach (string usingDirective in usingDirectives)
{
writer.WriteLine("using {0};", usingDirective);
}
writer.WriteLine();
writer.WriteLine("namespace {0}", targetNamespace);
// etc
}
You may wish to write a helper type to allow simple indentation etc.
If these suggestions don't help, please give more details of your situation.
I know an answer has already been accepted but why not use an XSLT applied to the XML instead? this would mean that you could easily generate c#, vb.net, .net without having to recompile the app.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FileHandling
{
class Class1
{
static void Main()
{
Console.WriteLine("Enter data");
ConsoleKeyInfo k;
//Console.WriteLine(k.KeyChar + ", " + k.Key + ", " + k.Modifiers );
string str="";
char ch;
while (true)
{
k = Console.ReadKey();
if ((k.Modifiers == ConsoleModifiers.Control) && (k.KeyChar == 23))
{
Console.WriteLine("\b");
break;
}
if (k.Key == ConsoleKey.Enter)
{
Console.WriteLine("");
str += "\n";
}
ch = Convert.ToChar(k.KeyChar);
str += ch.ToString();
}
Console.WriteLine(str);
Console.Read();
}
}
}

Categories

Resources