How to read xml document in MVC core (1.0.0)? - asp.net-core

I'm new to web programming and decided to switch from .net 4.5 to .net core.
My project has a static xml document in the following location:
wwwroot/Countries/en-GB.xml
How would one go about reading the xml file at the specified path? Eventually I will convert the data to a SelectList.
In .net 4.5 I used DataSet's and HttpConext...MapPath to read the xml document which no longer works in core mvc.
Any advice is greatly welcome.

First of all don't put your data source into wwwroot folder, because it is served publicly. Take a look at official docs:
The web root of your app is the directory in your project for public,
static resources like css, js, and image files. The static files
middleware will only serve files from the web root directory (and
sub-directories) by default.
So move Countries folder in your project's root folder.
To read xml data, you can use XmlSerializer. I will try to show how to read xml file:
First i assume you have xml content like below:
<?xml version="1.0" encoding="UTF-8" ?>
<Container>
<Countries>
<Country>
<Code>Code1</Code>
<Title>Title1</Title>
</Country>
<Country>
<Code>Code2</Code>
<Title>Title2</Title>
</Country>
</Countries>
</Container>
First describe types
public class Country
{
public string Code { get; set; }
public string Title { get; set; }
}
public class Container
{
public Country[] Countries { get; set; }
}
After that create a service for xml deserialization:
public interface ICountryService
{
Country[] GetCountries();
}
public class CountryService : ICountryService
{
private readonly IHostingEnvironment _env;
public CountryService(IHostingEnvironment env)
{
_env = env;
}
public Country[] GetCountries()
{
XmlSerializer ser = new XmlSerializer(typeof(Container));
FileStream myFileStream = new FileStream(_env.ContentRootPath + "\\Countries\\en-GB.xml", FileMode.Open);
return ((Container)ser.Deserialize(myFileStream)).Countries;
}
}
Then register service in ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddSingleton<ICountryService, CountryService>();
}
Finally inject and use it anywhere(such as in a controller)
public class SomeController : Controller
{
public SomeController(ICountryService countryService)
{
// use it
}
}

Related

Localization using single resource file for Views in Asp .Net Core 3.1

I am working on localization and I want to create a global resource file for all the strings for all views. I created resource files for model, controller and view but I need a global type of resource file that can store key value pair for Views. I don't don't know how to achieve this and where should I store my global resource file? Should I store it in models or services or in controllers?
in your Resources folder add the following files: (do your necessary imports of the code needed)
public class SharedViewLocalizer : ISharedViewLocalizer
{
private readonly IStringLocalizer localizer;
public SharedViewLocalizer(IStringLocalizerFactory factory)
{
var type = typeof(SharedResource);
var assemblyName = new AssemblyName(type.GetTypeInfo().Assembly.FullName);
this.localizer = factory.Create("SharedResource", assemblyName.Name);
}
public LocalizedString this[string key] => this.localizer[key];
public LocalizedString GetLocalizedString(string key)
{
return this.localizer[key];
}
}
public interface ISharedViewLocalizer
{
public LocalizedString this[string key]
{
get;
}
LocalizedString GetLocalizedString(string key);
}
public class SharedResource
{
}
add a file called SharedResource.en-US.resx in the resource folder
in your cshtml:
#using yourdirectory.Resources
#inject ISharedViewLocalizer Localizer
also don't forget to dependency inject
services.AddTransient<ISharedViewLocalizer, SharedViewLocalizer>();
If you have done all this in your cshtml you can then do:
Localizer["something"]
which will write the translation on the html page.
someone posted this: https://medium.com/#flouss/asp-net-core-localization-one-resx-to-rule-them-all-de5c07692fa4
special thanks to him.

ASP.NET Core Web API Error: Model 1[TContext] violates the Constraint of type 'TContext'

I have a Solution in Visual Studio 2017 that contains the following Projects:
CredentialManager.API (ASP.NET Core 2.1 Web API project)
CredentialManager.Models (Class Library that contains the Domain Model and Data Context Class)
The Domain Model Class is coded as follows:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CredentialManager.Models.Entities
{
public class Credential
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long CredentialId { get; set; }
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string Application { get; set; }
}
}
The Data Context Class is as follows:
using System;
using System.Collections.Generic;
using System.Text;
using CredentialManager.Models.Entities;
using Microsoft.EntityFrameworkCore;
namespace CredentialManager.Models.Context
{
public class CredentialManagerContext : DbContext
{
public CredentialManagerContext(DbContextOptions options)
: base(options)
{ }
public DbSet<Credential> Credentials { get; set; }
}
}
The appsettings.json file looks like the following:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"i.": null,
"CredentialManagerDB": "server=.\\SQLEXPRESS;database=CredentialManagerDB;Trusted_Connection=true;"
},
"AllowedHosts": "*"
}
The Startup.CS file looks like this:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<CredentialManagerContext>(o => o.UseSqlServer(Configuration["ConnectionStrings:CredentialManagerDB"]));
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
I then build the Solution and Added Migrations. But when I run update-database, I get the following error:
GenericArguments[0], 'CredentialManager.Models.Migrations.CredentialManagerContext', on 'Microsoft.EntityFrameworkCore.Design.IDesignTimeDbContextFactory`1[TContext]' violates the constraint of type 'TContext'.
Can someone here throw some light on this error ? If I include the classes and data context in the same folder as the API project, then everything works.. But I want these classes to be part of a separate Class Library Project. Any help would be much appreciated.
Thanks.
Update context file to have the following:
public CredentialManagerContext(DbContextOptions<CredentialManagerContext> options)
: base(options)
{ }
As outlined in the documentation:
This requires adding a constructor argument to your DbContext type that accepts :
DbContextOptions<TContext>
This should resolve your issue.
Thank you for all the suggestions. I found a Solution as well. The Startup.cs needs to be informed about the Project that contains the Migrations:
services.AddDbContext<CredManagerContext>(options => options.UseSqlServer(Configuration.GetConnectionString("CredentialManagerDB"), x => x.MigrationsAssembly("CredManager.Models")));
Everything works perfectly after this.

How to obtain the ASP.NET Core application name?

I would like do display in the footer of an ASP.NET Core 1.1
© 2017 MyApplication
<p>© 2017 #(ApplicationName)</p>
How do I get the application name?
I found an article on this subject but it's confusing about PlatformServices.Default.Application.ApplicationName, because it says do not use Microsoft.Extensions.PlatformAbstractions, but does not say what to use instead for the application name...
You could try:
#using System.Reflection;
<!DOCTYPE html>
<html>
....
<footer>
<p>© 2017 - #Assembly.GetEntryAssembly().GetName().Name</p>
</footer>
</html>
I am not sure it is a good way, but it works for me :)
There are a lot of way to achieve it. Here is how I do in my projects.
I normally have project name different from application name which could have spaces or much longer. So, I Keep the project name and version number in appsettings.json file.
appsettings.json
{
"AppSettings": {
"Application": {
"Name": "ASP.NET Core Active Directory Starter Kit",
"Version": "2017.07.1"
}
}
}
Startup.cs
Load setting from appsettings.json file into AppSettings POCO. It then automatically register in DI container as IOptions<AppSettings>.
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
}
AppSettings.cs
Note: I have some other settings so that I keep them all together inside AppSettings POCO.
public class AppSettings
{
public Application Application { get; set; }
}
public class Application
{
public string Name { get; set; }
public string Version { get; set; }
}
Usage (_layout.cshtml)
Inject IOptions<AppSettings> to View. You can also inject it to controller if you would like.
#inject IOptions<AppSettings> AppSettings
<footer class="main-footer">
#AppSettings.Value.Application.Version
#AppSettings.Value.Application.Name</strong>
</footer>

Can I use startup.cs to load AppSettings

Can I write code in startup.cs...Configuration method to call my DataAccess layer and/or some other class to assign data to my static class after reading the configurations either from DB or from AppSettings from web.config file to read all my app configurations during the startup. I've tried to access my Static Class in startup.cs by adding reference to the library where my class resided, but I'm not able to access it in my asp.net MVC4 app.
namespace CAS.Common
{
public static class CommonConfiguration
{
public static string CDSRestClient { get; set; }
public static string ClientIdValue { get; set; }
public static string ClientSecretValue { get; set; }
}
}
Code from Startup.cs
using System.Configuration;
using CAS.Common;
namespace myWebApp
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
//This is the intended code, which I'm not able to do as I'm not able to access my static class here.
CommonConfiguration.CDSRestClient = ConfigurationSettings.AppSettings["CDSRestClient"].ToString().Trim();
CommonConfiguration.ClientIdValue = ConfigurationSettings.AppSettings["clientIdValue"].ToString().Trim();
CommonConfiguration.ClientSecretValue = ConfigurationSettings.AppSettings["clientSecretValue"].ToString().Trim();
}
}
}
Can anyone tell me what am I doing wrong here.

Windsor webservice inject properties

I have a MVC application and inject my repositories to my controller what works properly.
Additionally I have a Webservice in my solution which uses exactly the same repositories but when my Webservice is called my repository properties are null.
I register my repositories the following way:
container.Register(Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient());
my repository properties look like:
public IUserRepository _userRepo { get; set; }
public IHdtRepository _hdtRepo { get; set; }
public ITimeRecordRepository _timeRepo { get; set; }
Can someone tell me why the repositories are not injected to my webservice?
For now I added the following to the constructor of my webservice:
public MyWebservice()
{
_userRepo = MvcApplication.container.Resolve<IUserRepository>();
_hdtRepo = MvcApplication.container.Resolve<IHdtRepository>();
_timeRepo = MvcApplication.container.Resolve<ITimeRecordRepository>();
_locationRepo = MvcApplication.container.Resolve<ILocationRepository>();
_wayRepo = MvcApplication.container.Resolve<IWayPointRepository>();
_wayDataRepo = MvcApplication.container.Resolve<IWayDataRepository>();
}
but as far as I know this is actually a antipattern.
I'm new to all that IoC stuff so could someone please tell me where the problem is.
Cheers,
Stefan
First lets get your project setup with some Windsor installers. They look like this for the most part.
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IEncryptionService().ImplementedBy<EncryptionService>());
}
}
in your App_Start folder add a class called ContainerConfig.cs that could look something like this.
public class ContainerConfig
{
private static IWindsorContainer _container;
public static IWindsorContainer ConfigureContainer()
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency"));
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
_container.AddFacility<TypedFactoryFacility>();
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
return _container;
}
}
Please note that I have a separate project for my Dependency Injection hence the _container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency")); line... You can remove the latter .Install(FromAssembly) part.
In your Global.asax you can do something like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ContainerConfig.ConfigureContainer();
}
Now in your controllers you can do this:
public class TempController : Controller
{
private readonly IEncryptionService _encryptionService;
public TempController(IEncryptionService encryptionService )
{
_encryptionService = encryptionService;
}
public ActionResult Index()
{
// Example of calling a method on the encryption service.
string hash, salt;
_encryptionService.GethashAndSaltString("I Need Some Loving", out hash, out salt);
return View();
}
}
Please let me know if you get something working with constructor injection. Solving that issue will be a great help going forward and you won't be using property injection. Once we get all of that sorted out we can look at your webervice issues.
I guess this is not possible as far as I've read some other posts.
The problem is that you can't create a custom factory for a Webservice like "WindsorControllerFactory" for the controller.
I'm going to switch to WCF Service.
Resolve a System.Web.Services.WebService instance with Castle (for AOP purposes)