Leaving the question of weather this is a good practice or not, there is a way to have multiple submit buttons on a single form. Clicking on any of the buttons will post to the same action, so how do you tell which one was clicked.
On your View:
[HttpPost]
public ActionResult Profile(Model model,string submitButton)
{
Member member = new Member();
switch (submitButton)
{
case "Save1": //do something;
break;
case "Save2": //do something;
break;
}
return View(model);
}
In one of my projects I needed to dynamically display fields to enter information for a collection of objects. Specifically speaking I had a POCO "User" class with FK to a POCO "Child" class. I needed a way to generate text boxes based on how many kids a user had. This involves several steps and here's what I had to do.
1. Create a partial view with the fields you need to capture the info for a "Child"
@{
var seed = ViewBag.Seed;
@{
@*MVC renders fields for a collection by appending an index, which I am setting up below*@
var ageIdText = "Children_" + seed + "__Age";
var ageNameText = "Children[" + seed + "].Age";
var genderIdText = "Children_" + seed + "__Gender";
var genderNameText = "Children[" + seed + "].Gender";
var deleteIdText = "Children_" + seed + "__Delete";
var deleteNameText = "Children[" + seed + "].Delete";
}
Remove
}
MVC renders controls for collections by attaching an index for the collection. I had to code this in to render based on the number of controls that need to be displayed. Ex: the age text field will be Children_[1]__Age and so forth. I will explain the reason for having a delete field a little later.
2. Create an action in the controller that will return the partial view
public ActionResult RenderChildren(int? id, int? seed, string viewType)
{
//if no of children to be rendered in the view was not send in the request url, then render only one child
if (id.HasValue)
ViewBag.Children = id;
else
ViewBag.Children = 1;
//if the collection index was not indicated, then start rendering the controls from 0.
//This will come in handy when there are already controls on the page and we want to add more.
if (seed.HasValue)
ViewBag.Seed = seed;
else
ViewBag.Seed = 0;
return PartialView(viewType);
}
It is important to keep track on the index for the collection, or you will get unexpected results.
3. Create the javascript that will call the action above from another control. ex: onclick event of a link that should add the control for adding a "Child"
function addChild(method,container,type) {
var noofChild = $(container).find('.mark-for-delete').length;
$.get('/account/'+method+'?seed=' + (noofChild)+"&viewtype="+type, function (template) { $(container).append(template); });
}
function deleteChildren(element, deleteElement) {
$container = $(element).parent();
$container.find(deleteElement).val('True');
$container.hide();
}
This will take care of dynamically rendering the required number of fields for "Child"
5. Handling the deletes - I also needed to provide the user to delete existing fields
To handle the delete I need some more javascript code that will add some value to the hidden field that I added to my partial view. This value can then be picked up via the model while updating the database. I do have a property in the "Child" POCO class for setting the delete value. This field is not mapped to the database.
You can use Winrar to create self-executing installer from the msi's and setup files you create from a Visual Studio Setup project.
Here are the steps:
1. Put your MSI and exe files in a folder.
2. Right click folder and select "Add to Archive"
3. Make sure that the archive format is set to "RAR" and check "Create SFX Archive" and "Create Solid Archive". The archive name extension automatically changes to ".exe"
4. Click on the "Advanced" tab and click on the "SFX Options" button.
5. In the "Advanced SFX Options" dialog - enter the path name to your .exe file. In my case "\Program\Setup.exe".
6. Click on the "Modes" tab and select "Hide all" under "Silent Mode" radio button group.
7. Click on Update tab. I set the "Overwrite All Files" as my overwrite mode. This will replace all install files.
8. To set an icon to your installer, click on the "Text and Icon" tab and set your options
9. Click OK on both the open dialogs and you'll have your self-extracting exe
There are several other options you can change based on your needs.
I ran into an interesting situation on a site using forms authentication, where the user had to be logged into both a domain and its subdomain once authenticated. Here's what I had to do to get this to work.
Both sites being seperate applications in themselves the authentication cookies generated by asp.net would be different due the encryption keys used by the sites. The Auth cookie generate by domain.com cannot be read by subdomain.domain.com. To get over this issue we need to add a machine key element in the web.config's of the both the apps. This key is going to be the same in both apps.
There are several different options in setting up these keys. Read more about it in this page. It also includes some code on how to generate a machine key using a console app - http://msdn.microsoft.com/en-us/library/ff649308.aspx
Once this is taken care of, the next issue we are going to have is the cookie itself. When a cookie is created - it is domain specific, so a cookie created by a sub domain will not be accessible to its parent level domain. In my case, the user authentication was to be performed on a subdomain using MVC. So I had to generate cookies for both the sub domain and domain upon authentication from my subdomain.
For Login
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
Account account = new Account();
//modify the Domain attribute of the cookie to the second level domain
HttpCookie MyCookie = FormsAuthentication.GetAuthCookie(model.UserName, model.RememberMe);
MyCookie.Domain = "domain.com";//the second level domain name
Response.AppendCookie(MyCookie);
string userName = account.GetUserName(model.UserName);
Session["ActualName"] = userName;
HttpCookie userCookie = new HttpCookie("IGNUS");
userCookie.Domain = "domain.com";
userCookie.Values["Name"] = userName;
if (model.RememberMe)
userCookie.Expires = DateTime.Now.AddDays(2);
Response.Cookies.Add(userCookie);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Member");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
I was trying to read an image from a URL using webclient, but it kept erroring out with a GDI+ error when I was trying to save it. The image in question is Tiff, but the same code worked when it was JPG - strange!!
But anyway I was able to get around this issue after stumbling across the following MSDN article: http://support.microsoft.com/?id=814675
using (Stream ms = new MemoryStream(client.DownloadData("http://image.com")))
{
Image img = Image.FromStream(ms);
Bitmap bmp = img as Bitmap;
Graphics g = Graphics.FromImage(bmp);
Bitmap bmpNew = new Bitmap(bmp);
g.DrawImage(bmpNew, new Point(0, 0));
g.Dispose();
bmp.Dispose();
img.Dispose();
bmpNew.Save("C:\\image.tiff");
}
Its really nice to work with classes rather than parsing the XML structure using Xpath or the old fashioned XML reader. You can use XSD.exe to generate a c# class based on the XML document or XML schema and then use it to output an XML file. 1. Open VS command prompt. 2. CD to the location where your XSD file is. 3. Type in XSD -c -l:c# -n:[your namespace] [XSD filename] This will generate a c# class. You can use that class along with the following code to output an XML file
XmlSerializer xmlSerializer = new XmlSerializer(typeof([Your Class]));
using (XmlWriter writer = XmlWriter.Create("[Path]"))
{
xmlSerializer.Serialize(writer, [instance of your class]); writer.Close();
}
I was trying to get the value of a DataGridViewCheckBoxColumn in order to see if the checkbox is checked or not. But I was getting a null value everytime. After scratching my head for a while and some googling I found that I needed to invoke the CommitEdit method to get the value of the checkbox state.
I was trying to move my .Net SqlServer 2008 to another dev machine and I kept getting this error, even thought I have the SqlServerSpatial.dll file in my bin. If you are getting the same error, do the following:
1. Make sure the SqlServerSpatial.dll file is in the bin of the application (you can find this dll on the machine that you have SqlServer2008 installed in the C:\Windows\System32 folder) 2. Make sure you have the latest VC++ redistributables installed. Turns out SqlServerSpatial.dll relies on VC++. You can download these redistributables for 32 bit (here) and 64 bit (here). 3. If you are still getting the error even after doing the above two, try running the SqlServer types installer to register the dll's with GAC.