I have a simple application. When a user logs in it creates a session variable and redirects them to another controller that pull up some info from the database. I need to store this to a session variable then return it to the view. The initial part is fine, it returns it and I see the information. However, when I try to create a search query it returns that the session is null even though I never clear it.
public ActionResult ShowCourses()
{
if (Session["Username"] != null)
{
string Username = Session["Username"].ToString();
using (DefaultConnection db = new DefaultConnection())
{
var model = from c in db.Courses
where c.Username == Username
select c;
Session["Courses"] = model.ToList();
var Courses = Session["Courses"];
return View(Courses);
}
}
else
{
return RedirectToAction("Login", "Users");
}
}
But when I try to run a search query to loop through the session, it brings back that Courses is null. The problem is that coursesQuery returns null and I'm not sure why.
public ActionResult SearchCourses(string query)
{
if (Session["Username"] != null)
{
var coursesQuery = Session["Courses"] as IEnumerable<Course>;
if (coursesQuery != null)
{
// Do Something
}
}
}
You did a .ToList() on the course colleciton before setting to Session.
Try this. Use List<Course> when you read it back.
if (Session["Courses"] != null)
{
var coursesQuery = (List<Course>) Session["Courses"];
}
Related
I wanted to check if the productDiscount entity is already exist in the database, if it is exist then I wanted to update it. But instead of updating the entity the following code adds a new one. How to solve this problem..
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ProductDiscount(ProductDiscount productDiscount)
{
if (!ModelState.IsValid)
{
var viewModel = new ViewModelProductDiscount()
{
Products = _context.Products.ToList()
};
return View(viewModel);
}
var id = productDiscount.ProductId;
var disInDb = _context.ProductDiscounts.FirstOrDefault(p => p.ProductId == id);
if (disInDb==null)
{
_context.ProductDiscounts.Add(productDiscount);
_context.SaveChanges();
}
else
{
_context.ProductDiscounts.Add(disInDb);
_context.SaveChanges();
return Content(disInDb.Id.ToString());
}
return RedirectToAction("Products");
}
from the else block remove _context.ProductDiscounts.Add(disInDb); Just map the productDiscount values into disInDb and then _context.SaveChanges();
Like
else
{
disInDb.Name = productDiscount.Name;
disInDb.Discription = productDiscount.Discription;
_context.SaveChanges();
}
I don't really know how your ProductDiscount object looks like so I will assume your object props but it should give you an idea of how to update the record. Inside your else this line _context.ProductDiscounts.Add(disInDb); is what is causing the issue. Instead you want to do the following inside the else block
else
{
disInDb.DiscountCode = "somecode"; //change this to the correct prop name which needs updating
disInDb.DiscountProductName = "somename"; //change this to the correct prop name which needs updating
_context.SaveChanges();
}
I try to put a file into a richtext but it crashes !
In my first code, I try to use directly "getFirstItem", in first time it was ok but now i try to use it again and it crashed.
In second time i pass with an object and it find my obj doesn't an richtextItem (instanceof) ???
I don't understand.
I have the message : "lotus.domino.local.Item cannot be cast to lotus.domino.RichTextItem" ?
Could you help me ?
public void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) throws NotesException {
lotus.domino.Session session = Utils.getSession();
lotus.domino.Database db = session.getCurrentDatabase();
lotus.domino.Document monDoc = db.getDocumentByUNID(idDocument);
lotus.domino.RichTextItem rtiNew = null;
try {
try {
if (monDoc != null) {
// if (monDoc.getFirstItem(nomRti) != null) {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.getFirstItem(nomRti);
// } else {
// rtiNew = (lotus.domino.RichTextItem)
// monDoc.createRichTextItem(nomRti);
// }
Object obj = null;
if (monDoc.getFirstItem(nomRti) != null) {
obj = monDoc.getFirstItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
} else {
obj = monDoc.createRichTextItem(nomRti);
if (obj instanceof lotus.domino.RichTextItem) {
rtiNew = (lotus.domino.RichTextItem) obj;
}
}
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtiNew.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
}
} finally {
rtiNew.recycle();
monDoc.recycle();
db.recycle();
session.recycle();
}
} catch (Exception e) {
e.printStackTrace();
}
}
EDIT : I try to modify my code with yours advices but the items never considerate as richtextitem. It is my problem. I don't understand why, because in my field it is a richtext ! For it, the item can't do :
rtiNew = (lotus.domino.RichTextItem) item1;
because item1 not be a richtext !!!
I was trying to take all the fields and pass in the item one by one, and it never go to the obj instance of lotus.domini.RichTextItem....
Vector items = doc.getItems();
for (int i=0; i<items.size(); i++) {
// get next element from the Vector (returns java.lang.Object)
Object obj = items.elementAt(i);
// is the item a RichTextItem?
if (obj instanceof RichTextItem) {
// yes it is - cast it as such // it never go here !!
rt = (RichTextItem)obj;
} else {
// nope - cast it as an Item
item = (Item)obj;
}
}
A couple of things. First of all I would set up a util class method to handle the object recycling in a neater way:
public enum DominoUtil {
;
public static void recycle(Base... bases) {
for (Base base : bases) {
if (base != null) {
try {
base.recycle();
} catch (Exception e) {
// Do nothing
}
}
}
}
}
Secondly I would remove the reduntants try/catch blocks and simplify it like this:
private void copieFichierDansRichText(String idDocument, String nomRti, File file,
String nameFichier, String chemin) {
Session session = DominoUtils.getCurrentSession();
Database db = session.getCurrentDatabase();
Document monDoc = null;
try {
monDoc = db.getDocumentByUNID(idDocument);
Item item = monDoc.getFirstItem(nomRti);
if (item == null) {
item = monDoc.createRichTextItem(nomRti);
} else if (item.getType() != Item.RICHTEXT) {
// The item is not a rich text item
// What are you going to do now?
}
RichTextItem rtItem = (RichTextItem) item;
PieceJointe pieceJointe = new PieceJointe();
pieceJointe = buildPieceJointe(file, nameFichier, chemin);
rtItem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, "", pieceJointe.getChemin()
+ pieceJointe.getNomPiece(), pieceJointe.getNomPiece());
monDoc.computeWithForm(true, false);
monDoc.save(true);
} catch (NotesException e) {
throw new FacesException(e);
} finally {
DominoUtil.recycle(monDoc);
}
}
Finally, apart from the monDoc, you need not recycle anything else. Actually Session would be automatically recycled and anything beneath with it (so no need to recycle db, let alone the session!, good rule is don't recycle what you didn't instantiate), but it's not bad to keep the habit of keeping an eye on what you instantiate. If it were a loop with many documents you definitively want to do that. If you also worked with many items you would want to recycle them as early as possible. Anyway, considered the scope of the code it's sufficient like this. Obviously you would call DominoUtil.recycle directly from the try block. If you have multiple objects you can recycle them at once possibly by listing them in the reverse order you set them (eg. DominoUtil.recycle(item, doc, view)).
Also, what I think you miss is the check on the item in case it's not a RichTextItem - and therefore can't be cast. I put a comment where I think you should decide what to do before proceeding. If you let it like that and let the code proceed you will have the code throw an error. Always better to catch the lower level exception and re-throw a higher one (you don't want the end user to know more than it is necessary to know). In this case I went for the simplest thing: wrapped NotesException in a FacesException.
I am using asp,net core and have used the tutorial to create sorted, paged and search page (Index). Once I edit an item from this page the controller always dumps me back to the default index page. How do I return to the previous URL. Many thanks.
Here is a section of my controller file.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Bind("id,UserPassword,user")] UserProfiles userProfiles)
{
var users = from u in _context.UserProfiles
select u;
if (id != userProfiles.id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(userProfiles);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserProfilesExists(userProfiles.id))
{
return NotFound();
}
else
{
throw;
}
}
// ***************
// Redirect to the previous URL,i.e. the Index
return Redirect(TempData["PreviousURL"].ToString()) ;
}
return View(userProfiles);
}
public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? page)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
// paging
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
// search
ViewData["CurrentFilter"] = searchString;
var users = from u in _context.UserProfiles
select u;
if (!String.IsNullOrEmpty(searchString))
{
users = users.Where(u => u.user.Contains(searchString)
);
}
//sort
switch (sortOrder)
{
case "name_desc":
users = users.OrderByDescending(u => u.user);
break;
default:
users = users.OrderBy(s => s.user);
break;
}
// ***************
// store the current path and query string in TempData["PreviousURL" session variable
TempData["PreviousURL"] = HttpContext.Request.Path.ToString() + HttpContext.Request.QueryString.ToString();
return View(await PaginatedList<UserProfiles>.CreateAsync(users.AsNoTracking(), page ?? 1, pageSize));
}
This is my first MVC project.
It depends on your logic where controller takes you after saving data.
You need to pass search, sort and paging related data to controller when saving data. You can send them as part of extra post data, as query string parameters or as part of the model itself which is being posted.
After saving data retrieve data based on those parameters and populater your view with that paged, filtred and sorted data.
I solved my problem with the use of session variables: ViewData, ViewBag and TempData. The following two pages were very useful:
https://www.codeproject.com/Articles/476967/What-is-ViewData-ViewBag-and-TempData-MVC-Option
http://andrewlock.net/an-introduction-to-session-storage-in-asp-net-core/
Please see edited question above for the solution.
I am using SQL Server and database triggers to keep a data-level audit of all changes to the system. This audit includes the userID / name of whomever initiated a change. Ideally I'd like to do something like this in my AppHost.Configure method:
SqlServerDialect.Provider.UseUnicode = true;
var dbFactory = new OrmLiteConnectionFactory(ConnectionString, SqlServerDialect.Provider)
{
ConnectionFilter = (db =>
{
IAuthSession session = this.Request.GetSession();
if (session != null && !session.UserName.IsNullOrEmpty())
{
System.Data.IDbCommand cmd = db.CreateCommand();
cmd.CommandText = "declare #ci varbinary(128); select #ci = CAST(#Username as varbinary(128)); set context_info #ci";
System.Data.IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "Username";
param.DbType = System.Data.DbType.String;
//param.Value = session.UserName;
param.Value = session.UserAuthId;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
return new ProfiledDbConnection(db, Profiler.Current);
}),
AutoDisposeConnection = true
};
container.Register<IDbConnectionFactory>(dbFactory);
Of course, this doesn't work because this.Request doesn't exist. Is there any way to access the current session from the ConnectionFilter or ExecFilter on an OrmLite connection?
The other approach I had started, doing an override of the Db property of Service, doesn't work any more because I've abstracted some activities into their own interfaced implementations to allow for mocks during testing. Each of these is passed a function that is expected to return the a DB connection. Example:
// Transaction processor
container.Register<ITransactionProcessor>(new MockTransactionProcessor(() => dbFactory.OpenDbConnection()));
So, how can I ensure that any DML executed has the (admittedly database-specific) context information needed for my database audit triggers?
The earlier multi tenant ServiceStack example shows how you can use the Request Context to store per-request items, e.g. you can populate the Request Context from a Global Request filter:
GlobalRequestFilters.Add((req, res, dto) =>
{
var session = req.GetSession();
if (session != null)
RequestContext.Instance.Items.Add(
"UserName", session.UserName);
});
And access it within your Connection Filter:
ConnectionFilter = (db =>
{
var userName = RequestContext.Instance.Items["UserName"] as string;
if (!userName.IsNullOrEmpty()) {
//...
}
}),
Another approach is to use a factory pattern, similar to how ServiceStack creates OrmLite db connections in the first place. Since all user-associated calls are made via the ServiceRunner, I piggy-back off of the session that's managed by ServiceStack.
public class TransactionProcessorFactory : ITransactionProcessorFactory
{
public ITransactionProcessor CreateTransactionProcessor(IDbConnection Db)
{
return new TransactionProcessor(Db);
}
}
public abstract MyBaseService : Service
{
private IDbConnection db;
public override System.Data.IDbConnection Db
{
get
{
if (this.db != null) return db;
this.db = this.TryResolve<IDbConnectionFactory>().OpenDbConnection();
IAuthSession session = this.Request.GetSession();
if (session != null && !session.UserName.IsNullOrEmpty())
{
IDbCommand cmd = db.CreateCommand();
cmd.CommandText = "declare #ci varbinary(128); select #ci = CAST(#Username as varbinary(128)); set context_info #ci";
IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "Username";
param.DbType = DbType.String;
//param.Value = session.UserName;
param.Value = session.UserAuthId;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
return db;
}
}
private ITransactionProcessor tp = null;
public virtual ITransactionProcessor TransactionProcessor
{
get
{
if (this.tp != null) return tp;
var factory = this.TryResolve<ITransactionProcessorFactory>();
this.tp = factory.CreateTransactionProcessor(this.Db);
return tp;
}
}
}
For the sake of potential future ServiceStack users, another approach would be to use OrmLite's Global Insert/Update filters combined with Mythz's approach above to inject the necessary SQL only when DML actions are made. It isn't 100%, since there may be stored procs or manual SQL, but that's potentially handled via an IDbConnection extension method to manually set desired auditing information.
I'm trying to filter some records using the RecordFilter interface. In my app I have a couple of interfaces similar to this one, on which the user can enter an ID or Name (he/she could enter both or neither of them too)
Here's what I've done so far:
The Customer filter.
Here if the user didn't enter an ID, I pass 0 as a default value, that's why I evaluate customerID!=0
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
private int mID_Filter;
public CustomerFilter(String name_Filter, int id_Filter) {
this.mName_Filter = name_Filter.toLowerCase();
this.mID_Filter = id_Filter;
}
public boolean matches(byte[] candidate) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
int customerID = dis.readInt();
String customerName = dis.readUTF().toLowerCase();
if ((customerName != null && customerName.indexOf(mName_Filter) != -1) && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName != null && customerName.indexOf(mName_Filter) != -1 && customerID == 0)
return true;
if (customerName == null && (customerID != 0 && customerID == mID_Filter))
return true;
if (customerName == null && customerID == 0)
return true;
} catch (IOException ex) {
//What's the point in catching a exception here???
}
return false;
}
}
The search method:
Note: This method is in a class that I call "RMSCustomer", in which I deal with everything related to RMS access. The search method receives two parameters (id and name) and uses them to instantiate the filter.
public Customer[] search(int id, String name) throws RecordStoreException, IOException {
RecordStore rs = null;
RecordEnumeration recEnum = null;
Customer[] customerList = null;
try {
rs = RecordStore.openRecordStore(mRecordStoreName, true);
if (rs.getNumRecords() > 0) {
CustomerFilter filter = new CustomerFilter(name, id);
try {
recEnum = rs.enumerateRecords(filter, null, false);
if (recEnum.numRecords() > 0) {
customerList = new Customer[recEnum.numRecords()];
int counter = 0;
while (recEnum.hasNextElement()) {
Customer cust;
int idRecord = recEnum.nextRecordId();
byte[] filterRecord = rs.getRecord(idRecord);
cust = parseRecord(filterRecord);
cust.idRecord = idRecord;
customerList[counter] = cust;
counter++;
}
}
else{
customerList = new Customer[0];
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please select another filter"
}
} finally {
recEnum.destroy();
}
}
else{
//How to send a message to the midlet from here
//saying something like "No Record Exists.Please Add record"
}
} finally {
rs.closeRecordStore();
}
return customerList;
}
Even though, the code shown above works I still have some questions/problems:
In the Filter :
1) How can I improve the code that evaluates the possible values of the filters (name,id)? What if I had more filters?? Will I have to test all the possible combinations??
2) If the user doesn’t enter neither a ID nor a name, should I display all the records or should I display a message "Please enter a name or ID"?? What would you do in this case?
3) Why do I have to put a try-catch in the filter when I can't do anything there?? I can't show any alert from there or can I?
In the search method:
1) How can I show a proper message to the user from that method? something like "No records" (see the "ELSE" parts in my code
Sorry If I asked too many questions, it's just that there's any complete example of filters.
Thanks in advance
How can I improve the code that evaluates the possible values of the
filters (name,id)?
The ID is the first field in the record and the fastest one to search for. If the Id matches, It doesn't really matter what the customer name is. Normally you'll be looking for the records where the ID matches OR the customer name matches, so once the ID matches you can return true. This is my proposal for the CustomerFilter class:
public class CustomerFilter implements RecordFilter {
private String mName_Filter;
//Use Integer instead of int.
//This way we can use null instead of zero if the user didn't type an ID.
//This allows us to store IDs with values like 0, -1, etc.
//It is a bit less memory efficient,
//but you are not creating hundreds of filters, are you? (If you are, don't).
private Integer mID_Filter;
public CustomerFilter(String name_Filter, Integer id_Filter) {
this.mName_Filter = normalizeString(mName_Filter);
this.mID_Filter = id_Filter;
}
//You should move this function to an StringUtils class and make it public.
//Other filters might need it in the future.
private static String normalizeString(final String s){
if(s != null){
//Warning: you might want to replace accentuated chars as well.
return s.toLowerCase();
}
return null;
}
public boolean matches(byte[] candidate) {
ByteArrayInputStream bis = new ByteArrayInputStream(candidate);
DataInputStream dis = new DataInputStream(bis);
try {
if(mID_Filter != null){
//If the ID is unique, and the search is ID OR other fields, this is fine
int customerID = dis.readInt();
if(mID_Filter.intValue == customerID){
return true;
} else {
return false;
}
}
if(mName_Filter != null){
String customerName = normalizeString(dis.readUTF());
if(customerName != null && customerName.indexOf(mName_Filter) != -1){
return true;
}
}
if(mID_Filter == null && mName_Filter == null){
return true; // No filtering, every record matches.
}
} catch (IOException ex) {
//Never swallow exceptions.
//Even if you are using an underlying ByteArrayInputStream, an exception
//can still be thrown when reading from DataInputStream if you try to read
//fields that do not exists.
//But even if no exceptions were ever thrown, never swallow exceptions :)
System.err.println(ex);
//Optional: throw ex;
} finally {
//Always close streams.
if(bis != null){
try {
bis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
if(dis != null){
try {
dis.close();
} catch(IOException ioe){
System.err.println(ioe);
}
}
}
return false;
}
}
What if I had more filters?? Will I have to test all the possible
combinations??
It depends on your project. Usually the ID is unique and no two records exist with the same id. In this case you should explicitly design the screen so that the user understands that either he types an Id, or else he fills in the other fields. The condition would be like this:
idMatches OR (field1Matches AND field2Matches AND ... fieldNMatches)
If the user types nothing, then all records will be returned.
But then again this is more a UX issue, I don't know if it is valid for your requirements.
From the programming point of view, what is clear is that the more fields you add, the more messy your filter will became. To prevent this, you could use patterns like Decorator, Composite, and even Chain of responsibility. You'll probably have to trade good design for performance though.
If the user doesn’t enter neither a ID nor a name, should I display
all the records or should I display a message "Please enter a name or
ID"?? What would you do in this case?
It depends. Is there any other way to view all records? If so, then show the message.
Why do I have to put a try-catch in the filter when I can't do
anything there?? I can't show any alert from there or can I?
You shouldn't. This class is only responsible of filtering, not of interacting with the user. You can still log the error from the catch clause, and then throw the exception again. That will propagate the exception up to RMSCustomer.search, so whatever client code is calling that function will handle the exception in the same way you are handling the other ones thrown by that method. But keep the finally clause to close the streams.
How can I show a proper message to the user from that method?
something like "No records" (see the "ELSE" parts in my code)
You shouldn't do anything related to the GUI (like showing dialogs) from the RMSCustomer class. Even if you are not using the Model-View-Controller pattern, you still want to keep your class focused on a single responsibility (managing records). This is called the Single responsibility principle.
Keeping your class isolated from the GUI will allow you to test it and reuse it in environments without GUI.
The no records case should be handled by the screen when there are zero results. An array of lenght == 0 is fine here, and the screen will show the "No results" message. For other kinds of errors, you can extend the Exception class and throw your own custom exceptions, i.e: RecordParsingException, from the RMSCustomer.search method. The screen class will then map the different exceptions to the error message in the language of the user.