Hello,
I created a few Repositories to manage some XML files.
Since the repositories share the same files I wanted all to work under a same session (Unit Of Work Pattern).
So the Context, that implements ISession, contains a field _model that contains all the XDocument requested by the repositories.
A repository can request a XDocument by using the Context Register method.
If the file does not exist in model then it is loaded and returned. If exists then it is only returned.
The change submission runs with session.Commit() which saves all XML files.
Here I think I could have a method, Rollover, to dispose the XDocuments without saving them? Can I "unload" XDocuments? In each repository I access the files after registering and add them to private fields inside the repository ...
Maybe I could improve this? Maybe accessing the context directly?
Finally I have a FileService. For each product in the XML file might be a photograph.
So I save a Guid in the XML file and save the file with that name.
The FileService has a Queue where it saves the files and the action to take: Delete, Create, ...
When the session is submitted the actions are performed.
Maybe here I could add a method so when the session is rolleback the queue would become empty? This is for a small project that should use XML files.
I have this running and it is working .
I am just looking to improve it or detect some mistakes that I didn't detected.
public interface ISession {
Boolean Commit();
FileService FileService { get; set; }
XDocument Register(String key);
} // ISession
public partial class Context : ISession {
private IDictionary<String, XDocument> _model;
private String _path;
public FileService FileService { get; set; }
public Context(String path) {
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path", "Path cannot be null");
_model = new Dictionary<String, XDocument>();
_path = Path.IsPathRooted(path) ? path : HostingEnvironment.MapPath(path);
this.FileService = new FileService(String.Format("{0}/{1}", _path, "File"));
this.FileService.Queue = new Queue<FileEntry>();
} // Context
public Boolean Commit() {
try {
// Commit model
foreach (KeyValuePair<String, XDocument> e in _model)
e.Value.Save(new Uri(e.Value.BaseUri).LocalPath);
// Commit queue
this.FileService.Commit();
return true;
} catch (Exception) {
return false;
}
} // Commit
public XDocument Register(String key) {
if (!_model.ContainsKey(key))
_model.Add(key, XDocument.Load(Path.Combine(_path, String.Concat(key, ".xml")), LoadOptions.SetBaseUri));
return _model.FirstOrDefault(e => e.Key == key).Value;
} // Register
} // Context
public class SlideRepository {
private XDocument _albums;
private XDocument _slides;
private FileService _fileService;
public SlideRepository(ISession session) {
if (session == null)
throw new ArgumentNullException("session", "Session cannot be null");
_albums = session.Register("Albums");
_slides = session.Register("Slides");
_fileService = session.FileService;
} // SlideRepository
public void Create(Slide slide) {
Int32 id = (Int32)_slides.Root.Attribute("Id");
XElement _slide = new XElement("Slide",
new XElement("Id", id),
new XElement("AlbumId", slide.Album.Id),
new XElement("Photograph", Guid.NewGuid())
);
_fileService.Queue.Enqueue(new FileEntry { Action = FileAction.Create, Content = slide.Photograph, Filename = (String)_slide.Element("Photograph") });
_albums.Root.SetAttributeValue("Id", id + 1);
_slides.Root.Add(_slide);
} // Create
public void DeleteById(Int32 id) {
XElement slide = _slides.Root.Elements("Slide").FirstOrDefault(s => (Int32)s.Element("Id") == id);
_fileService.Queue.Enqueue(new FileEntry { Action = FileAction.Delete, Filename = (String)slide.Element("Photograph") });
slide.Remove();
} // DeleteById
public Slide FindById(Int32 id) {
return _slides.Root.Elements("Slide").Select(s => new Slide {
Id = (Int32)s.Element("Id"),
Album = _albums.Root.Elements("Album").Where(a => (Int32)a.Element("Id") == (Int32)s.Element("AlbumId")).Select(a => new Album {
Id = (Int32)a.Element("Id"),
Name = (String)a.Element("Name")
}).FirstOrDefault(),
Photograph = _fileService.Find((String)s.Element("Photograph"))
}).FirstOrDefault(s => s.Id == id);
} // FindById
public void Update(Slide slide) {
XElement _slide = _slides.Root.Elements("Slide").FirstOrDefault(s => (Int32)s.Element("Id") == (Int32)slide.Id);
if (_slide != null) {
_slide.SetElementValue("AlbumId", slide.Album.Id);
if (slide.Photograph.Length != 0)
_fileService.Queue.Enqueue(new FileEntry { Action = FileAction.Update, Content = slide.Photograph, Filename = (String)_slide.Element("Photograph") });
}
} // Update
} // SlideRepository
And here is the FileService:
public class FileService {
private String _path;
public Queue<FileEntry> Queue { get; set; }
public FileService(String path) {
if (String.IsNullOrEmpty(path))
throw new ArgumentNullException("path", "Path cannot be null");
_path = path;
} // FileService
public void Commit() {
while (Queue.Count > 0) {
FileEntry f = Queue.Dequeue();
switch (f.Action) {
case FileAction.Create:
Create(f.Content, f.Filename);
break;
case FileAction.Delete:
Delete(f.Filename);
break;
case FileAction.Update:
Update(f.Content, f.Filename);
break;
}
}
} // Commit
public void Create(Byte[] content, String filename) {
FileStream stream = new FileStream(String.Format("{0}/{1}", _path, filename), FileMode.Create, FileAccess.ReadWrite);
BinaryWriter writer = new BinaryWriter(stream);
writer.Write(content);
writer.Close();
} // Create
public void Delete(String filename) {
File.Delete(String.Format("{0}/{1}", _path, filename));
} // Delete
public Byte[] Find(String filename) {
if (File.Exists(String.Format("{0}/{1}", _path, filename)))
return File.ReadAllBytes(String.Format("{0}/{1}", _path, filename));
else
return null;
} // Find
public void Update(Byte[] content, String filename) {
Create(content, filename);
} // Update
} // FileService
Any suggestion is welcome.
Thank You,
Miguel