I am having some trouble. I have a Telerik editor where I display I file that is housed in my application. I need to save the changes back to the file. But some things also get saved to back to the database. My save button currently does save back to the database, but I don't know how to also make the file save the changes made. Here is my page code:

@model BbkValidation.Models.Task
@{
    ViewBag.Title = "Edit";
}
<!--<h2>Edit</h2>-->
<h2>@Html.DisplayFor(model => model.Title)</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        @Html.HiddenFor(model => model.TaskID)
        @Html.HiddenFor(model => model.Title)
        @Html.HiddenFor(model => model.Url)
        <div style="overflow: auto; width: 100%;">
           <div class="editor-field;" style="margin-top: 5px; margin-bottom: 20px; float: left">
                Task Status<br />
                @Html.RadioButton("Status", "Open") Open<br />
                @Html.RadioButton("Status", "Meditech") Meditech<br />
                @Html.RadioButton("Status", "Closed") Closed<br />
                @Html.ValidationMessageFor(model => model.Status)
            </div>
            <div style="float: right; margin-top: 5px; margin-bottom: 5px; margin-left: 17px">
                Notes<br />
                @Html.TextAreaFor(model => model.Notes)
                @Html.ValidationMessageFor(model => model.Notes)
            </div>

           <div>
           @{
                string htmlFilePath = "~/TaskHtml/" + Model.Url;
                string fileContents = "";
                string physicalPath = Server.MapPath(htmlFilePath);
                fileContents = File.ReadAllText(physicalPath);

                Html.Telerik().Editor()
                    .Name("editor")
                    .HtmlAttributes(new { style = "height:500px; width:99%;frameborder:0" })
                    .Encode(false)
                    .Value(@fileContents).Render();


            }


           </div> 
        </div>
        <p>
            <input type="submit" value="Save" />&nbsp;&nbsp;&nbsp;
            @Html.ActionLink("Cancel, back to list", "Index")

        </p>

        <!-- other content -->


    </fieldset>

}

Here is my task controller code:

namespace BbkValidation.Controllers
{
    public class TasksController : Controller
    {
        private TaskDBContext db = new TaskDBContext();

        //
        // GET: /Tasks/

        /*************start original
        public ViewResult Index()
        {
            return View(db.Tasks.ToList());
        }
        ***********************************end orig*/
        //[Authorize(Roles = @"IS Users")]
        public ViewResult Index(string sortOrder, string searchString)
        {
            ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
            ViewBag.StatusSortParm = sortOrder == "Status" ? "Status desc" : "Status";
            var tasks = from t in db.Tasks
                        select t;

            if (!String.IsNullOrEmpty(searchString))
            {
                tasks = tasks.Where(t => t.Title.Contains(searchString));
            }

            switch (sortOrder)
            {
                case "Name desc":
                    tasks = tasks.OrderByDescending(t => t.Title);
                    break;
                case "Status desc":
                    tasks = tasks.OrderBy(t => t.Status);
                    break;
                default:
                    tasks = tasks.OrderBy(t => t.TaskID);
                    break;
            }
            return View(tasks.ToList());
        }

        //
        // GET: /Tasks/Details/5

        //[Authorize(Roles = @"IS Users")]
        public ViewResult Details(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // GET: /Tasks/Create

        //[Authorize(Roles = @"IS Users")]
        public ActionResult Create()
        {

            return View();
        }

        //
        // POST: /Tasks/Create

        [HttpPost]
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Create(Task task)
        {
            if (ModelState.IsValid)
            {
                db.Tasks.Add(task);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(task);
        }

        //
        // GET: /Tasks/Edit/5

        //[Authorize(Roles = @"IS Users")]
        public ActionResult Edit(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // POST: /Tasks/Edit/5

        [HttpPost]
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Edit(Task task)
        {
            if (ModelState.IsValid)
            {
                db.Entry(task).State = EntityState.Modified;
                db.SaveChanges();

                return RedirectToAction("Index");
            }
            return View(task);
        }

        //

        // GET: /Tasks/Delete/5
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Delete(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // POST: /Tasks/Delete/5
        //[Authorize(Roles = @"IS Users")]
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            Task task = db.Tasks.Find(id);
            db.Tasks.Remove(task);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        //[Authorize(Roles = @"IS Users")]
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }

        //[HttpGet]
        //public ActionResult ShowFile()
        //{
        //    string filepath = Server.MapPath("~/~/TaskHtml/(model => model.Url)");
        //    string content = string.Empty;

        //    try
        //    {
        //        using (var stream = new StreamReader(filepath))
        //        {
        //            content = stream.ReadToEnd();
        //        }
        //    }
        //    catch (Exception exc)
        //    {
        //        return Content("Uh oh!");
        //    }

        //    return Content(content);
        //}  

    }
}

And here is my model code:

namespace BbkValidation.Models
{
    public class Task
    {
        public int TaskID { get; set; }
        public string Title { get; set; }
        public string Status { get; set; }
        public string Url { get; set; }
        public string Notes { get; set; }

    }

    public class TaskDBContext : DbContext
    {
        public DbSet<Task> Tasks { get; set; }
    }
}

Please let mw know what I can do. Thank you.

Recommended Answers

All 17 Replies

Hi Jesi,

In this code:

            string htmlFilePath = "~/TaskHtml/" + Model.Url;
            string fileContents = "";
            string physicalPath = Server.MapPath(htmlFilePath);
            fileContents = File.ReadAllText(physicalPath);

you are reading the contents of a file and then you pass the text into the Telerik editor but I don't see anywhere that you are saving the text back to the file.

If this were my code I would add a FileContents property to my model ( you can use partial classes to add properties to entities). I would then add the above code as a private method to my controller that returns a string (the file contents) that can then be called from any of my CRUD (Create,Update,Delete) ActionResults. Then I could simply do this:

task.FileContents = GetFileContents(path);

before passing my model to my view.

After adding the FileContents property to my model I would have to make sure that my Telerik Editor control had the name FileContents so the view passed it back in my model. Then in the controller I would have another method:

private void WriteFileContents(string path, string contents) {
    File.WriteAllText(path, contents);
}

which I would call after a successfull save to my database that would write the contents of the file back out to disk.

I hope this helps.

Sorry, I got put on another project for a while, but I am still confused.

Here is my model and by the way this is my first MVC project so I am just confused by MVC to tell you the truth:

namespace BbkValidation.Models
{
    public class Task
    {
        public int TaskID { get; set; }
        public string Title { get; set; }
        public string Status { get; set; }
        public string Url { get; set; }
        public string Notes { get; set; }

    }

    public class TaskDBContext : DbContext
    {
        public DbSet<Task> Tasks { get; set; }
    }
}

So you are say just add

public string FileContents{get; set;}

To that? Or does it have to be a separate method. Sorry I really don't understand...

The model should have a property added like this one:

public string FileContents {get;set;}

Then you want to move this code:

if (!String.IsNullOrEmpty(searchString))
{
    tasks = tasks.Where(t => t.Title.Contains(searchString));   

    string htmlFilePath = "~/TaskHtml/" + Model.Url;
    string fileContents = "";
    string physicalPath = Server.MapPath(htmlFilePath);
    task.FileContents = File.ReadAllText(physicalPath);
}

into your TaskController ActionResult (or as a private method that you pass your model into before passing it to your view)

Then in your view file:

Html.Telerik().Editor()
.Name("editor")
.HtmlAttributes(new { style = "height:500px; width:99%;frameborder:0" })
.Encode(false)
.Value(Model.FileContents).Render();

Then in all your HTTPPOST methods you have to pass the Model.FileContents to a method like this:

public ActionResult MyPostMehtod(Task task) {
    if(Model.IsValid) {
        WriteFileContents("c:\filepath\file.txt", task.FileContents);
        return View();
     }
     ...
}
//This method is what saves your file back to disk.
private void WriteFileContents(string path, string contents) {
    File.WriteAllText(path, contents);
}

Good Luck

When I use your example I get an error:

System.Web.Mvc.Controller.File(string, string, string)' is a 'method', which is not valid in the given context

for this line:

File.WriteAllText(path, contents);

and this line:

task.FileContents = File.ReadAllText(physicalPath);

Ok, I got through that I just had to System.IO before the File. But I am having a different issue now with the code. It does not like this part of the code:

task.FileContents = File.ReadAllText(physicalPath);

I add this to my controller:

public string FileContents {get;set;}

But the error I get states it does not have a definition for 'FileContents'

Help :( I am confused.

You should have added

public string FileContents {get;set;}

to your task model like this:

namespace BbkValidation.Models
 {
     public class Task
     {
         public int TaskID { get; set; }
         public string Title { get; set; }
         public string Status { get; set; }
         public string Url { get; set; }
         public string Notes { get; set; }
           public string FileContents { get; set; }
     }
     public class TaskDBContext : DbContext
     {
         public DbSet<Task> Tasks { get; set; }
     }
 }

not to your controller.

That is what my Model does look like, sorry I used the wrong terminally, so I stll get that same error. Thank you.

Can you post the entire stack trace for this error?

Also, are you using Visual Studio?

Yes, I am using isual Studio 2010. Error as follows:

'System.Linq.IQueryable<BbkValidation.Models.Task>' does not contain a definition for 'FileContents' and no extension method 'FileContents' accepting a first argument of type 'System.Linq.IQueryable<BbkValidation.Models.Task>' could be found (are you missing a using directive or an assembly reference?)

This line:

'FileContents' accepting a first argument of type 'System.Linq.IQueryable<BbkValidation.Models.Task>'

is saying that instead of passing a string to FileContents, somewhere you are trying to set it to a Queryable of Task. If you are debugging in visual studio is should break on the line that is causing the problem.

If you can't figure this out please paste your new versions of the model, controller and view.

Model:

namespace BbkValidation.Models
{
    public class Task
    {
        public int TaskID { get; set; }
        public string Title { get; set; }
        public string Status { get; set; }
        public string Url { get; set; }
        public string Notes { get; set; }
        public string FileContents { get; set; }

    }

    public class TaskDBContext : DbContext
    {
        public DbSet<Task> Tasks { get; set; }
    }
}

Contoller:

namespace BbkValidation.Controllers
{
    public class TasksController : Controller
    {
        private TaskDBContext db = new TaskDBContext();

        //
        // GET: /Tasks/

        /*************start original
        public ViewResult Index()
        {
            return View(db.Tasks.ToList());
        }
        ***********************************end orig*/
        //[Authorize(Roles = @"IS Users")]
        public ViewResult Index(string sortOrder, string searchString)
        {
            ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Name desc" : "";
            ViewBag.StatusSortParm = sortOrder == "Status" ? "Status desc" : "Status";
            var tasks = from t in db.Tasks
                        select t;

            if (!String.IsNullOrEmpty(searchString))
            {
                tasks = tasks.Where(t => t.Title.Contains(searchString));

                string htmlFilePath = "~/TaskHtml/" + Model.Url; //get error for Model
                string fileContents = "";
                string physicalPath = Server.MapPath(htmlFilePath);
                task.FileContents = System.IO.File.ReadAllText(physicalPath); //get error fpr FileContents
            }

            switch (sortOrder)
            {
                case "Name desc":
                    tasks = tasks.OrderByDescending(t => t.Title);
                    break;
                case "Status desc":
                    tasks = tasks.OrderBy(t => t.Status);
                    break;
                default:
                    tasks = tasks.OrderBy(t => t.TaskID);
                    break;
            }
            return View(tasks.ToList());
        }

        //
        // GET: /Tasks/Details/5

        //[Authorize(Roles = @"IS Users")]
        public ViewResult Details(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // GET: /Tasks/Create

        //[Authorize(Roles = @"IS Users")]
        public ActionResult Create()
        {

            return View();
        }

        //
        // POST: /Tasks/Create

        [HttpPost]
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Create(Task task)
        {
            if (ModelState.IsValid)
            {
                db.Tasks.Add(task);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(task);
        }

        //
        // GET: /Tasks/Edit/5

        //[Authorize(Roles = @"IS Users")]
        public ActionResult Edit(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // POST: /Tasks/Edit/5

        [HttpPost]
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Edit(Task task)
        {
            if (ModelState.IsValid)
            {
                db.Entry(task).State = EntityState.Modified;
                WriteFileContents("'~/TaskHtml/' + Url", task.FileContents);
                db.SaveChanges();

                return RedirectToAction("Index");
            }
            return View(task);
        }

        //

        // GET: /Tasks/Delete/5
        //[Authorize(Roles = @"IS Users")]
        public ActionResult Delete(int id)
        {
            Task task = db.Tasks.Find(id);
            return View(task);
        }

        //
        // POST: /Tasks/Delete/5
        //[Authorize(Roles = @"IS Users")]
        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            Task task = db.Tasks.Find(id);
            db.Tasks.Remove(task);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        //[Authorize(Roles = @"IS Users")]
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        } 
        private void WriteFileContents(string path, string contents) 
        {
            System.IO.File.WriteAllText(path, contents);
        }

    }
}

View:

@model BbkValidation.Models.Task
@{
    ViewBag.Title = "Edit";
}
<!--<h2>Edit</h2>-->
<h2>@Html.DisplayFor(model => model.Title)</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        @Html.HiddenFor(model => model.TaskID)
        @Html.HiddenFor(model => model.Title)
        @Html.HiddenFor(model => model.Url)
        <div style="overflow: auto; width: 100%;">
           <div class="editor-field;" style="margin-top: 5px; margin-bottom: 20px; float: left">
                Task Status<br />
                @Html.RadioButton("Status", "Open") Open<br />
                @Html.RadioButton("Status", "Meditech") Meditech<br />
                @Html.RadioButton("Status", "Closed") Closed<br />
                @Html.ValidationMessageFor(model => model.Status)
            </div>
            <div style="float: right; margin-top: 5px; margin-bottom: 5px; margin-left: 17px">
                Notes<br />
                @Html.TextAreaFor(model => model.Notes)
                @Html.ValidationMessageFor(model => model.Notes)
            </div>

           <div>
           @{

                Html.Telerik().Editor()
                    .Name("editor")
                    .HtmlAttributes(new { style = "height:500px; width:99%;frameborder:0" })
                    .Encode(false)
                    .Value(Model.FileContents).Render();


            }


           </div> 
        </div>
        <p>
            <input type="submit" value="Save" />&nbsp;&nbsp;&nbsp;
            @Html.ActionLink("Cancel, back to list", "Index")

        </p>

        <!-- other content -->


    </fieldset>

}

Thank you.

First I have a question. Is there a file for each task? The reason I ask is that in your Index controller viewresult you are passing in a IQueryable result as the model and you are trying to assign a string to task.FileContents which hasn't even been instantiated yet.

You are getting an error in this line:

string htmlFilePath = "~/TaskHtml/" + Model.Url; //get error for Model

becuase you have not created a Model variable yet. There is not a Model member in the controller so you have to create the model which you have done with tasks variable.

I know this becuase when you do this:

return View(tasks.ToList());

you are passing the model to the view.

If there is a File for each individual task you need to iterate your tasks and assign the contents of each file to each tasks. Something like this:

foreach (var task in tasks) {
    task.FileContents = System.IO.File.ReadAllText(Server.MapPath("~/TaskHtml/" + task.Url))
}

and then pass tasks to the View just like you're doing.

I also noticed that you are trying to write FileContents in your HttpPost Edit ActionResult but when you pass the task into edit you are not yet assigning the contents of the file to FileContents.

There is more but lets try to get these fixed first.

I added that as suggested, but I get an error at boths task, but I changed it to tasks, and now I get an error at FileContents and URL. States no defination exists for ethier of those. Obviously I do not know what I am doing...

If you are able, and you want to, please zip the project up and attach it to a reply. I will take a look at it for you.

I have zipped it and attached it. The database is also attached. Thank you. I don't think the file upload worked though so I do not think it will allow me to.

The file attachment didn't work. Maybe you could just use a public dropbox folder and give me the url.

I'm glad everything is working now. Please mark this thread as solved. Thanks.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.