How to reference resource from Resources file - asp.net-core

I have a bunch of messages in a Constants file that I want to convert all string constants for messages displayed to users to be moved to a localized/globalization resource file.
I created a Resources.resx file and I'm trying to figure out how to reference a resource in a controller. For example this resource in my Resources.resx file
internal static string ItemUpdateFailed {
get {
return ResourceManager.GetString("ItemUpdateFailed", resourceCulture);
}
}
I want to reference it in a controller action to replace the bolded reference to the string constant in the method below. How do I reference the resource above in the method below.
public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
var itemIndexViewModel = new ItemIndexViewModel();
try
{
_mapper.Map(await _itemService.GetItemAsync(ItemStatus.Active, cancellationToken).ConfigureAwait(true), itemIndexViewModel.Items);
}
catch
{
**TempData.Put(TempDataKey.Item.UPDATE_MESSAGE, StatusMessageModel.Create(Constants.Item.TO_CREATE_UPDATE_FAIL));**
}
return View(itemIndexViewModel);
}

Related

ASP.NET Core 7 WebApplicationFactory Integration tests. How to load data?

I am creating an integration test to check that the data is working based on this very good tutorial.
The tutorial loads sample data in the OnModelCreating. But I was unsure if doing that will repeatedly load data to the DB when running the program.
However although I can get the index page to load, it has the page content, such as the table structure for the data it doesn't have the data from the database.
Using Swagger I copied a sample of data as JSON, saved it to a file, capitalized the first letter of the key to make it the same as the properties (after not doing do was fruitless as well), and tried to add it to the context.
internal static class AddTestData
{
//import json array and add to context
public static void AddMovieData(ApplicationDbContext context)
{
var jsonString = File.ReadAllText("testMoviedata.json");
var list = JsonSerializer.Deserialize<List<Movie>>(jsonString);
{
foreach (var item in list)
{
context.Movie.Add(item);
}
context.SaveChanges();
}
}
}
and tried to add it to the dbcontext in this process in the WebApplicationFactory Class from HERE
public class TestingWebAppFactory<TEntryPoint> : WebApplicationFactory<Program> where TEntryPoint : Program
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
......... stuff deleted for brevity...
using (var appContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>())
{
try
{
appContext.Database.EnsureCreated();
// Seed the database with test data.
AddTestData.AddMovieData(appContext);
}
catch (Exception ex)
{
//Log errors or do anything you think it's needed
throw;
}
}
... still nothin. Page loads, no data loads.
Also why can't I get breakpoints to work in the Integration project?
What am I doing wrong?
Solved!!!
The code was OK,but the data wasn't being deserialised.
I had to move it to the main project and test it there.
The solution is
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var list = JsonSerializer.Deserialize<Movie[]>(jsonString, options);

Why documentt.data.getValue() gives empty string? [duplicate]

A custom object that takes a parameter of (DocumentSnapShot documentsnapShot). also is an inner object from Firebase that retrieves a snapshot and set the values to my custom model also have its argument (DocumentSnapShot documentsnapShot). However, I wish to get the data from Firebase and pass it to my custom argument because mine takes multiple data not only Firebase. And it's not possible to iterate Firestore without an override.
Here's the code:
public UserSettings getUserSettings(DocumentSnapshot documentSnapshot){
Log.d(TAG, "getUserSettings: retrieving user account settings from firestore");
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
settings.setDisplay_name(documentSnapshot.getString("display_name"));
settings.setUsername(documentSnapshot.getString("username"));
settings.setWebsite(documentSnapshot.getString("website"));
settings.setProfile_photo(documentSnapshot.getString("profile_photo"));
settings.setPosts(documentSnapshot.getLong("posts"));
settings.setFollowers(documentSnapshot.getLong("followers"));
settings.setFollowing(documentSnapshot.getLong("following"));
}
});
}
You cannot return something now that hasn't been loaded yet. Firestore loads data asynchronously, since it may take some time for this. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available. If you want to pass settings object to another method, just call that method inside onSuccess() method and pass that object as an argument. So a quick fix would be this:
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
yourMethod(settings);
}
One more thing to mention is that you don't need to set the those values to object that already have them. You are already getting the data from the database as an object.
So remember, onSuccess() method has an asynchronous behaviour, which means that is called even before you are getting the data from your database. If you want to use the settings object outside that method, you need to create your own callback. To achieve this, first you need to create an interface like this:
public interface MyCallback {
void onCallback(UserAccountSettings settings);
}
Then you need to create a method that is actually getting the data from the database. This method should look like this:
public void readData(MyCallback myCallback) {
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
myCallback.onCallback(settings);
}
});
}
In the end just simply call readData() method and pass an instance of the MyCallback interface as an argument wherever you need it like this:
readData(new MyCallback() {
#Override
public void onCallback(UserAccountSettings settings) {
Log.d("TAG", settings.getDisplay_name());
}
});
This is the only way in which you can use that object of UserAccountSettings class outside onSuccess() method. For more informations, you can take also a look at this video.
Use LiveData as return type and observe the changes of it's value to execute desired operation.
private MutableLiveData<UserAccountSettings> userSettingsMutableLiveData = new MutableLiveData<>();
public MutableLiveData<UserAccountSettings> getUserSettings(DocumentSnapshot documentSnapshot){
DocumentReference mSettings = mFirebaseFirestore.collection("user_account_settings").document(userID);
mSettings.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
UserAccountSettings settings = documentSnapshot.toObject(UserAccountSettings.class);
settings.setDisplay_name(documentSnapshot.getString("display_name"));
settings.setUsername(documentSnapshot.getString("username"));
settings.setWebsite(documentSnapshot.getString("website"));
settings.setProfile_photo(documentSnapshot.getString("profile_photo"));
settings.setPosts(documentSnapshot.getLong("posts"));
settings.setFollowers(documentSnapshot.getLong("followers"));
settings.setFollowing(documentSnapshot.getLong("following"));
userSettingsMutableLiveData.setValue(settings);
}
});
return userSettingsMutableLiveData;
}
Then from your Activity/Fragment observe the LiveData and inside onChanged do your desired operation.
getUserSettings().observe(this, new Observer<UserAccountSettings>() {
#Override
public void onChanged(UserAccountSettings userAccountSettings) {
//here, do whatever you want on `userAccountSettings`
}
});

Android QBCustomObject file uploading The resource wasn't found error

I am trying to upload file using QBCustomObjectFiles ,uploading starts to show progress in log cat ,but with file field is null and response throws error like this '{"errors":["The resource wasn't found"]}'
I checked My Note Class on Quickblox admin panel,everything seems OK.Also I checked the file (field in method parameter) and it is not null as showing in log cat
public void uploadNote(Note note, File file,
QBEntityCallback<QBCustomObjectFileField> callback, QBProgressCallback
progressCallback) {
QBCustomObject customObject = new QBCustomObject();
customObject.setClassName(Note.Contract.CLASS_NAME_NOTE);
customObject.put(Note.Contract.COURSE_ID,note.getCourseId());
customObject.put(Note.Contract.CATEGORY_ID,note.getCategoryId());
customObject.put(Note.Contract.DESCRIPTION,note.getDescription());
customObject.put(Note.Contract.TOPIC,note.getTopic());
QBCustomObjectsFiles.uploadFile(file, customObject, "noteFile", progressCallback).performAsync(callback);
}
This is my log cat :
REQUEST
POST https://api.quickblox.com/data/Note/null/file.json
HEADERS
QuickBlox-REST-API-Version=0.1.1
QB-SDK=Android 3.9.1
QB-Token=011a2bc55be67185d4d045d8b2d31
PARAMETERS
field_name=noteFile
INLINE
POST https://api.quickblox.com/data/Note/null/file.json?field_name=noteFile
and this is response
'{"errors":["The resource wasn't found"]}'
The Uploading starts and shows progress ,but after progress 100 it throws above error.
You should use QBContent instead of QBCustomObjectsFiles. Example:
QBContent.uploadFileTask(file, isPublic, tags, new QBProgressCallback() {
#Override
public void onProgressUpdate(int progressValue) {
//some code for progress
}
}).performAsync(new QBEntityCallback<QBFile>() {
#Override
public void onSuccess(QBFile qbFile, Bundle params) {
//some code for success upload
}
#Override
public void onError(QBResponseException responseException) {
//some code for error upload
}
});

How can I write to a file in wwwroot with Asp.Net core 2.0 Webapi

I need a very simple API to allow for the Posting of certain keys.
This keys should be written on a file, but I am having trouble after deploying the app, as I can read the file on a GET Request but the posting does not work.
The message it gives me is
"detail": "Access to the path '....\Keys\Keys.json' is denied.",
Code I am using to write to file:
var path = "wwwroot/Keys/Keys.json";
var result = new List <FireBaseKeysModel> ( );
if (System.IO.File.Exists (path)) {
var initialJson = System.IO.File.ReadAllText (path);
var convertedJson =
JsonConvert.DeserializeObject <List <FireBaseKeysModel>> (initialJson);
try {
result.AddRange (convertedJson);
}
catch {
//
}
}
result.Add(new FireBaseKeysModel() {
AccountId = accountId,
AditionalInfo = addicionalInfo,
DeviceInfo = deviceInfo,
RegistrationKey = registrationKey,
ClientId = clientId
});
var json = JsonConvert.SerializeObject (result.ToArray ( ));
System.IO.File.WriteAllText (path, json);
Anyway I can fix this without needint to change permissions on the server itself?
I have similar task that I need to take logged-in users' upload files and store them on the server. I chose to store them under the folder structure wwwroot/uploads/{ environment }/{ username }/{ YYYY }/{ MM }/{ DD }/.
I am not giving you the exact answer to your problem but these are the steps you might want to try.
Enable static file usage
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
// With the usage of static file extensions, you shouldn't need to
// set permissions to folders, if you decide to go with wwwroot.
app.UseStaticFiles();
...
}
Storage service
public interface IStorageService
{
Task<string> UploadAsync(string path, IFormFile content, string
nameWithoutExtension = null);
}
public class LocalFileStorageService : IStorageService
{
private readonly IHostingEnvironment _env;
public LocalFileStorageService(IHostingEnvironment env)
{
_env = env;
}
public async Task<string> UploadAsync(string path, IFormFile content,
string nameWithoutExtension = null)
{
if (content != null && content.Length > 0)
{
string extension = Path.GetExtension(content.FileName);
// Never trust user's provided file name
string fileName = $"{ nameWithoutExtension ?? Guid.NewGuid().ToString() }{ extension }";
// Combine the path with web root and my folder of choice,
// "uploads"
path = Path.Combine(_env.WebRootPath, "uploads", path).ToLower();
// If the path doesn't exist, create it.
// In your case, you might not need it if you're going
// to make sure your `keys.json` file is always there.
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// Combine the path with the file name
string fullFileLocation = Path.Combine(path, fileName).ToLower();
// If your case, you might just need to open your
// `keys.json` and append text on it.
// Note that there is FileMode.Append too you might want to
// take a look.
using (var fileStream = new FileStream(fullFileLocation, FileMode.Create))
{
await Content.CopyToAsync(fileStream);
}
// I only want to get its relative path
return fullFileLocation.Replace(_env.WebRootPath,
String.Empty, StringComparison.OrdinalIgnoreCase);
}
return String.Empty;
}
}
There should not be a way to fix it without modifying permissions on that folder. (Since you are using System.IO I'm assuming this is Windows and IIS). The worker process usually uses the account that is running the application pool.
By default this account should only have read access to that folder. Without giving him, at least write permission, there should be no way to work around it.
Small off-topic comment: I would not hardcode the wwwroot folder, since the name of that folder is object to configuration and could very well change, I'd use the built in IHostingEnvironment and dependency injection to get the path:
private IHostingEnvironment _env;
public FooController(IHostingEnvironment env) {
_env = env;
}
var webrootFolder = _env.WebRootPath

Find Matching OperationContract Based on URI

...or "How to determine which WCF method will be called based on URI?"
In a WCF service, suppose a method is invoked and I have the URI that was used to invoke it. How can I get information about the WCF end point, method, parameters, etc. that the URI maps to?
[OperationContract]
[WebGet(UriTemplate = "/People/{id}")]
public Person GetPersonByID(int id)
{
//...
}
For instance, if the URI is: GET http://localhost/Contacts.svc/People/1, I want to get this information: service name (Service), Method (GetPersonByID), Parameters (PersonID=1). The point is to be able to listen for the request and then extract the details of the request in order to track the API call.
The service is hosted via http. This information is required before the .Net caching can kick in so each call (whether cached or not) can be tracked. This probably means doing this inside HttpApplication.BeginRequest.
FYI I'm hoping to not use reflection. I'd like to make use of the same methods WCF uses to determine this. E.g. MagicEndPointFinder.Resolve(uri)
Here is what I ended up doing, still interested if there is a cleaner way!
REST
private static class OperationContractResolver
{
private static readonly Dictionary<string, MethodInfo> RegularExpressionsByMethod = null;
static OperationContractResolver()
{
OperationContractResolver.RegularExpressionsByMethod = new Dictionary<string, MethodInfo>();
foreach (MethodInfo method in typeof(IREST).GetMethods())
{
WebGetAttribute attribute = (WebGetAttribute)method.GetCustomAttributes(typeof(WebGetAttribute), false).FirstOrDefault();
if (attribute != null)
{
string regex = attribute.UriTemplate;
//Escape question marks. Looks strange but replaces a literal "?" with "\?".
regex = Regex.Replace(regex, #"\?", #"\?");
//Replace all parameters.
regex = Regex.Replace(regex, #"\{[^/$\?]+?}", #"[^/$\?]+?");
//Add it to the dictionary.
OperationContractResolver.RegularExpressionsByMethod.Add(regex, method);
}
}
}
public static string ExtractApiCallInfo(string relativeUri)
{
foreach (string regex in OperationContractResolver.RegularExpressionsByMethod.Keys)
if (Regex.IsMatch(relativeUri, regex, RegexOptions.IgnoreCase))
return OperationContractResolver.RegularExpressionsByMethod[regex].Name;
return null;
}
}
SOAP
private static void TrackSoapApiCallInfo(HttpContext context)
{
string filePath = Path.GetTempFileName();
string title = null;
//Save the request content. (Unfortunately it can't be written to a stream directly.)
context.Request.SaveAs(filePath, false);
//If the title can't be extracted then it's not an API method call, ignore it.
try
{
//Read the name of the first element within the SOAP body.
using (XmlReader reader = XmlReader.Create(filePath))
{
if (!reader.EOF)
{
XmlNamespaceManager nsManager = new XmlNamespaceManager(reader.NameTable);
XDocument document = XDocument.Load(reader);
//Need to add the SOAP Envelope namespace to the name table.
nsManager.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
title = document.XPathSelectElement("s:Envelope/s:Body", nsManager).Elements().First().Name.LocalName;
}
}
//Delete the temporary file.
File.Delete(filePath);
}
catch { }
//Track the page view.
}