string Concatenate in yml file and use with aspnetcore 2.1 - asp.net-core

yml string concatenate does not work with .NET applications.I have tried by removing '$' sign, but it is still not working(Java application uses $ sign - Working fine with Java apps). It is working fine for a single value, but not with concatenation.
yml-01
cicd:
dbname: 172.10.10.110
port: 5432
yml-02
datasource:
url: jdbc:postgresql://${cicd:dbname}:${cicd:port}/sample-db

A solution for placeholder resolution in .NET Configuration (similar to that provided by spring) is available in Steeltoe.Common. We haven't added WebHostBuilder or IConfigurationBuilder extensions just yet, but if you add a recent reference to Steeltoe.Common from the Steeltoe Dev feed you should be able to do something like this:
public static IWebHostBuilder ResolveConfigurationPlaceholders(this IWebHostBuilder hostBuilder, LoggerFactory loggerFactory = null)
{
return hostBuilder.ConfigureAppConfiguration((builderContext, config) =>
{
config.AddInMemoryCollection(PropertyPlaceholderHelper.GetResolvedConfigurationPlaceholders(config.Build(), loggerFactory?.CreateLogger("Steeltoe.Configuration.PropertyPlaceholderHelper")));
});
}
The code above is used in the Steeltoe fork of eShopOnContainers

You should take a look at YamlDotNet.
Here's an example of how to solve your problem using that lib
using YamlDotNet.RepresentationModel;
using YamlDotNet.Core;
Then in your method
var dbname = "172.10.10.110";
var port = "5432";
string content;
using (var reader = new StreamReader("your yml file"))
{
content = reader.ReadToEnd();
}
var doc = new StringReader(content);
var yaml = new YamlStream();
yaml.Load(doc);
// Add the url where you use string interpolation to replace the values
var ymlFile = (YamlMappingNode)yaml.Documents[0].RootNode;
ymlFile.Children["datasource"] = new YamlMappingNode
{
{ "url", $"jdbc:postgresql://{dbname}:{port}/sample-db" }
};
yaml.Save(File.CreateText("C:\\yourNewFile.yml"), assignAnchors: false);
Here's a link to the NetCore package

I've solved this by writing an extension method to the IConfiguration interface.
public static string ReadFromConfigRepo(this IConfiguration configuration, string key)
{
var pattern = #"\{(.*?)\}";
var query = configuration[key];
if (query.Contains('{'))
{
var matches = Regex.Matches(query, pattern);
string value;
foreach (Match m in matches)
{
value = configuration[m.Value.Substring(1, m.Value.Length - 2)];
query = query.Replace(m.Value, value);
}
}
return query.Trim();
}

Related

Serilog Elasticsearch

i have a microservice api where I try to log all the request which come in...so the elasticsaerch service and kibana are on a different server. I'm using the serilog.sinks.elasticsearch package to send data to the elasticsearch.
Both servers are not running with docker, they are just normal windows server.
My code looks like this to setup the logging...
public static Logger Create(IConfiguration configuration)
{
var elasticsearchSection = configuration.GetSection("Elasticsearch");
if (elasticsearchSection != null)
{
return CreateLoggerConfiguration(elasticsearchSection).CreateLogger();
}
return null;
}
private static LoggerConfiguration CreateLoggerConfiguration(IConfigurationSection section)
{
var loggerConfiguration = new LoggerConfiguration();
var url = section.GetValue<string>("Url");
var minimumLogLevel = section.GetValue<string>("MinimumLogLevel");
var minimumLogEventLevel = section.GetValue<string>("MinimumLogEventLevel");
SetLoggerConfigurationMinimumLogLevel(minimumLogLevel, loggerConfiguration);
loggerConfiguration.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(GetLoggingUri(url))
{
MinimumLogEventLevel = ReturnLogEventLevel(minimumLogEventLevel),
AutoRegisterTemplate = true
});
loggerConfiguration.Enrich.FromLogContext();
return loggerConfiguration;
}
And in my startup,cs I'm using
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
in the ConfigureServices Method...
But apparently I cant create an Index inside my Kibana.
Any ideas why this isnt working?

Export html to pdf in ASP.NET Core

I want to export a piece of html to a pdf file but i do not any compatible nuget package.
When I try to install anyone: "X not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0)."
Does anyone know any way to export to a pdf using asp.net core??
You can use jsreport .net sdk if you are in .net core 2.0 also without more complex node services. This includes among other features filters to convert your existing razor views into pdf. From the docs:
1.
Install nugets jsreport.Binary, jsreport.Local and jsreport.AspNetCore
2.
In you Startup.cs configure it as the following
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddJsReport(new LocalReporting()
.UseBinary(JsReportBinary.GetBinary())
.AsUtility()
.Create());
}
3.
Then you need to add MiddlewareFilter attribute to the particular action and specify which conversion you want to use. In this case html to pdf conversion.
[MiddlewareFilter(typeof(JsReportPipeline))]
public IActionResult Invoice()
{
HttpContext.JsReportFeature().Recipe(Recipe.ChromePdf);
return View();
}
You can reach bunch of other options for headers, footers or page layout on JsReportFeature(). Note that the same way you can also produce excel files from html. See more information in the documentation.
PS: I'm the author of jsreport.
Copied from my original answer here Export to pdf using ASP.NET 5:
One way to generate pdf from html in .NET Core (without any .NET framework dependencies) is using Node.js from within the .NET Core application.
The following example shows how to implement an HTML to PDF converter in a clean ASP.NET Core Web Application project (Web API template).
Install the NuGet package Microsoft.AspNetCore.NodeServices
In Startup.cs add the line services.AddNodeServices() like this
public void ConfigureServices(IServiceCollection services)
{
// ... all your existing configuration is here ...
// Enable Node Services
services.AddNodeServices();
}
Now install the required Node.js packages:
From the command line change working directory to the root of the .NET Core project and run these commands.
npm init
and follow the instructions to create the package.json file
npm install jsreport-core --save
npm install jsreport-jsrender --save
npm install jsreport-phantom-pdf --save
Create a file pdf.js in the root of the project containing
module.exports = function (callback) {
var jsreport = require('jsreport-core')();
jsreport.init().then(function () {
return jsreport.render({
template: {
content: '<h1>Hello {{:foo}}</h1>',
engine: 'jsrender',
recipe: 'phantom-pdf'
},
data: {
foo: "world"
}
}).then(function (resp) {
callback(/* error */ null, resp.content.toJSON().data);
});
}).catch(function (e) {
callback(/* error */ e, null);
})
};
Have a look here for more explanation on jsreport-core.
Now create an action in an Mvc controller that calls this Node.js script
[HttpGet]
public async Task<IActionResult> MyAction([FromServices] INodeServices nodeServices)
{
var result = await nodeServices.InvokeAsync<byte[]>("./pdf");
HttpContext.Response.ContentType = "application/pdf";
string filename = #"report.pdf";
HttpContext.Response.Headers.Add("x-filename", filename);
HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "x-filename");
HttpContext.Response.Body.Write(result, 0, result.Length);
return new ContentResult();
}
Off course you can do whatever you want with the byte[] returned from nodeServices, in this example I'm just outputting it from a controller action so it can be viewed in the browser.
You could also exchange the data between Node.js and .NET Core by a base64 encoded string using resp.content.toString('base64') in pdf.js and use
var result = await nodeServices.InvokeAsync<byte[]>("./pdf"); in the action and then decode the base64 encoded string.
Alternatives
Most pdf generator solutions still depend on .NET 4.5/4.6 framework. But there seems to be some paid alternatives available if you don't like to use Node.js:
NReco.PdfGenerator.LT
EVO HTML to PDF Converter Client for .NET Core
Winnovative HTML to PDF Converter Client for .NET Core
I haven't tried any of these though.
I hope we will soon see some open source progress in this area.
You can check DinkToPdf library. It is a wrapper around wkhtmltopdf library for .NET Core.
Synchronized converter
Use this converter in multi threaded applications and web servers. Conversion tasks are saved to blocking collection and executed on a single thread.
var converter = new SynchronizedConverter(new PdfTools());
Define document to convert
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4Plus,
},
Objects = {
new ObjectSettings() {
PagesCount = true,
HtmlContent = #"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In consectetur mauris eget ultrices iaculis. Ut odio viverra, molestie lectus nec, venenatis turpis.",
WebSettings = { DefaultEncoding = "utf-8" },
HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true, Spacing = 2.812 }
}
}
};
I was having the same issue! I wanted to generate PDF files from HTML strings. I then came across PhantomJs which is a command line utility for converting html files to pdf. I wrote a cross-platform wrapper over it in C# for .NET CORE and its working great on Linux! Though as of now its only for 64-bit Linux, because that is the only platform .NET Core Supports currently.
The project can be found here
PhantomJs.NetCore.PdfGenerator gen = new PhantomJs.NetCore.PdfGenerator("/path/to/pantomjsfolder");
string outputFilePath = gen.GeneratePdf("<h1>Hello</h1>","/folder/to/write/file/in");
This is a solution working for ASP.NET Core 2.0, which allows either to generate dynamic PDF files from cshtml, directly send them to users and/or save them before sending.
To complement Jan Blaha answer there, for more flexibility, you may want to use the following code:
/// Generate a PDF from a html string
async Task<(string ContentType, MemoryStream GeneratedFileStream)> GeneratePDFAsync(string htmlContent)
{
IJsReportFeature feature = new JsReportFeature(HttpContext);
feature.Recipe(Recipe.PhantomPdf);
if (!feature.Enabled) return (null, null);
feature.RenderRequest.Template.Content = htmlContent;
var report = await _RenderService.RenderAsync(feature.RenderRequest);
var contentType = report.Meta.ContentType;
MemoryStream ms = new MemoryStream();
report.Content.CopyTo(ms);
return (contentType, ms);
}
Using a class to render cshtml files as string, you may use the following service (which can be injected as a scoped service):
public class ViewToStringRendererService: ViewExecutor
{
private ITempDataProvider _tempDataProvider;
private IServiceProvider _serviceProvider;
public ViewToStringRendererService(
IOptions<MvcViewOptions> viewOptions,
IHttpResponseStreamWriterFactory writerFactory,
ICompositeViewEngine viewEngine,
ITempDataDictionaryFactory tempDataFactory,
DiagnosticSource diagnosticSource,
IModelMetadataProvider modelMetadataProvider,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
: base(viewOptions, writerFactory, viewEngine, tempDataFactory, diagnosticSource, modelMetadataProvider)
{
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model)
{
var context = GetActionContext();
if (context == null) throw new ArgumentNullException(nameof(context));
var result = new ViewResult()
{
ViewData = new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
TempData = new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
ViewName = viewName,
};
var viewEngineResult = FindView(context, result);
viewEngineResult.EnsureSuccessful(originalLocations: null);
var view = viewEngineResult.View;
using (var output = new StringWriter())
{
var viewContext = new ViewContext(
context,
view,
new ViewDataDictionary<TModel>(
metadataProvider: new EmptyModelMetadataProvider(),
modelState: new ModelStateDictionary())
{
Model = model
},
new TempDataDictionary(
context.HttpContext,
_tempDataProvider),
output,
new HtmlHelperOptions());
await view.RenderAsync(viewContext);
return output.ToString();
}
}
private ActionContext GetActionContext()
{
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = _serviceProvider;
return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
}
/// <summary>
/// Attempts to find the <see cref="IView"/> associated with <paramref name="viewResult"/>.
/// </summary>
/// <param name="actionContext">The <see cref="ActionContext"/> associated with the current request.</param>
/// <param name="viewResult">The <see cref="ViewResult"/>.</param>
/// <returns>A <see cref="ViewEngineResult"/>.</returns>
ViewEngineResult FindView(ActionContext actionContext, ViewResult viewResult)
{
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
if (viewResult == null)
{
throw new ArgumentNullException(nameof(viewResult));
}
var viewEngine = viewResult.ViewEngine ?? ViewEngine;
var viewName = viewResult.ViewName ?? GetActionName(actionContext);
var result = viewEngine.GetView(executingFilePath: null, viewPath: viewName, isMainPage: true);
var originalResult = result;
if (!result.Success)
{
result = viewEngine.FindView(actionContext, viewName, isMainPage: true);
}
if (!result.Success)
{
if (originalResult.SearchedLocations.Any())
{
if (result.SearchedLocations.Any())
{
// Return a new ViewEngineResult listing all searched locations.
var locations = new List<string>(originalResult.SearchedLocations);
locations.AddRange(result.SearchedLocations);
result = ViewEngineResult.NotFound(viewName, locations);
}
else
{
// GetView() searched locations but FindView() did not. Use first ViewEngineResult.
result = originalResult;
}
}
}
if(!result.Success)
throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", viewName));
return result;
}
private const string ActionNameKey = "action";
private static string GetActionName(ActionContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
{
return null;
}
var actionDescriptor = context.ActionDescriptor;
string normalizedValue = null;
if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
!string.IsNullOrEmpty(value))
{
normalizedValue = value;
}
var stringRouteValue = routeValue?.ToString();
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
{
return normalizedValue;
}
return stringRouteValue;
}
}
Then to conclude, in your controller, supposing the razor cshtml view template to be /Views/Home/PDFTemplate.cshtml you may use the following.
Note: The cshtml file may need to be copied when published (even if views are compiled).
var htmlContent = await _ViewToStringRendererService.RenderViewToStringAsync("Home/PDFTemplate", viewModel);
(var contentType, var generatedFile) = await GeneratePDFAsync(htmlContent);
Response.Headers["Content-Disposition"] = $"attachment; filename=\"{System.Net.WebUtility.UrlEncode(fileName)}\"";
// You may save your file here
using (var fileStream = new FileStream(Path.Combine(folder, fileName), FileMode.Create))
{
await generatedFile.CopyToAsync(fileStream);
}
// You may need this for re-use of the stream
generatedFile.Seek(0, SeekOrigin.Begin);
return File(generatedFile.ToArray(), "application/pdf", fileName);
On the server-side, you can output pdf of a html and use library that generate PDF from HTML string .NET Core after you got pdf, you need to pass it to the library see this link to convert HTML to PDF in .NET.
install nuget package : Select.HtmlToPdf.NetCore
HtmlToPdf htmlToPdf = new HtmlToPdf();
htmlToPdf.Options.PdfPageOrientation = PdfPageOrientation.Portrait;
// put css in pdf
htmlToPdf.Options.MarginLeft = 15;
htmlToPdf.Options.MarginRight = 15;
---------------------------
string url = "<html><head></head><body>Hello World</body></html>"
PdfDocument pdfDocument = htmlToPdf.ConvertHtmlString(url);
byte[] pdf = pdfDocument.Save();
//convert to memory stream
Stream stream = new MemoryStream(pdf);
pdfDocument.Close();
//if want to transfer stream to file
File(stream, "application/pdf", Guid.NewGuid().ToString() + ".pdf");
For exporting html to pdf you can use itextsharp library and even you can place html inside a partial view and export that view as pdf. Recently , i have tried that in a project where i needed to export pdf and i got refer How to export view as pdf in Asp.Net core . So you can give this a try.

How to format ServiceStack Redis connection string

How can I format the below Redis connection string:
Connection string:
myIP,keepAlive=180,ConnectRetry=30,ConnectTimeout=5000
I started writing a unit test but keep getting a input string was not in correct format error message
[TestFixtureSetUp]
private void Init()
{
var redisConnectionString = "myIP,keepAlive=180,ConnectRetry=30,ConnectTimeout=5000";
_clientsManager = new PooledRedisClientManager(redisConnectionString);
}
[Test]
public void CanConnectToRedis()
{
var readWrite = (RedisClient) _clientsManager.GetClient();
using (var redis = _clientsManager.GetClient())
{
var redisClient = redis;
}
}
See the connection string format on the ServiceStack.Redis home page:
redis://localhost:6379?ConnectTimeout=5000&IdleTimeOutSecs=180
Which can be used in any of the Redis Client Managers:
var redisManager = new RedisManagerPool(
"redis://localhost:6379?ConnectTimeout=5000&IdleTimeOutSecs=180");
using (var client = redisManager.GetClient())
{
client.Info.PrintDump();
}
The list of available configuratoin options are also listed on the homepage.

How can I provide Metadata from my WCF service for consumption in Breeze

I am trying to adapt an existing WebApi/MVC4 app to use Breeze lookups.
Currently I retrieve my DTOs via
[HttpGet]
public IQueryable<ThingDto> GetThings()
{
var channelFactory = ThingServiceConfiguration.CreateChannelFactory();
_serviceFactory = () => new WcfProxy<IThingService>(channelFactory.CreateChannel());
var client = _serviceFactory();
IQueryable<ThingDto> result = client.Execute(p => p.GetThings()).OrderBy(x => x.Name).AsQueryable();
return result;
}
I'm not sure how I implement this method Metadata()
public string Metadata()
{
//normally something like this if using a EF DataContext
// return _someContextProvider.Context.Things;
}
How I setup the WCF config
public class ThingServiceConfiguration
{
const string AppSettingKey = "ThingServiceUrl";
public static ChannelFactory<IThingService> CreateChannelFactory()
{
// var serviceUrl = ConfigurationManager.AppSettings[AppSettingKey];
var serviceUrl = "http://localhost:86/ThingService.svc";
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
MaxReceivedMessageSize = 200000000,
SendTimeout = TimeSpan.FromMinutes(2),
ReceiveTimeout = TimeSpan.FromMinutes(2)
};
var address = new EndpointAddress(serviceUrl);
return new ChannelFactory<IThingService>(binding, address);
}
}
Could this metadata be provided with the WCF call into the Metadata() property (by providing arguments through BasicHttpBinding ?
Many thanks!
You can return Breeze 'native' metadata simply by returning the metadata in json form. Something like this:
[HttpGet]
public String Metadata() {
var folder = Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data");
// metadata.json is the name of a file containing your metadata - pick any file name you like.
var fileName = Path.Combine(folder, "metadata.json");
var jsonMetadata = File.ReadAllText(fileName);
return jsonMetadata;
}
where the syntax of the metadata file is described here: Breeze metadata format.

ASP.NET WebApi file upload using guid and file extension

I currently am able to save a file being uploaded to a WebAPI controller, but I'd like to be able to save the file as a guid with the correct file name extension so it can be viewed correctly.
Code:
[ValidationFilter]
public HttpResponseMessage UploadFile([FromUri]string AdditionalInformation)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
using (var requestStream = task.Result)
{
try
{
// how can I get the file extension of the content and append this to the file path below?
using (var fileStream = File.Create(HttpContext.Current.Server.MapPath("~/" + Guid.NewGuid().ToString())))
{
requestStream.CopyTo(fileStream);
}
}
catch (IOException)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response;
}
I can't seem to get a handle on the actual filename of the content. I thought headers.ContentDisposition.FileName might be a candidate but that doesn't seem to get populated.
Thanks for the comments above which pointed me in the right direction.
To clarify the final solution, I used a MultipartFormDataStreamProvider which streams the file automatically. The code is in another question I posted to a different problem here:
MultipartFormDataStreamProvider and preserving current HttpContext
My full provider code is listed below. The key to generating the guid file name is to override the GetLocalFileName function and use the headers.ContentDisposition property. The provider handles the streaming of the content to file.
public class MyFormDataStreamProvider : MultipartFormDataStreamProvider
{
public MyFormDataStreamProvider (string path)
: base(path)
{ }
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
// restrict what images can be selected
var extensions = new[] { "png", "gif", "jpg" };
var filename = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
if (filename.IndexOf('.') < 0)
return Stream.Null;
var extension = filename.Split('.').Last();
return extensions.Any(i => i.Equals(extension, StringComparison.InvariantCultureIgnoreCase))
? base.GetStream(parent, headers)
: Stream.Null;
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
// override the filename which is stored by the provider (by default is bodypart_x)
string oldfileName = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
string newFileName = Guid.NewGuid().ToString() + Path.GetExtension(oldfileName);
return newFileName;
}
}