ASMX Web Service, Stored Procedures and MVC Models - asp.net-mvc-3

I am developing a web application using MVC 3. This application connects to an SQL Server database through ASMX Web Services. Each Web Method calls a Stored Procedure and returns a DataTable.
This is the code I'm using to call the Stored Procedure:
public static DataTable ExecSP(string StoredProcedureName, List<string> ParameterNames, List<Object> ParameterValues)
{
SqlConnection Connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLServer"].ConnectionString);
SqlDataReader Reader = null;
DataTable SPResult = null;
try
{
Connection.Open();
SqlCommand Command = new SqlCommand("dbo." + StoredProcedureName, Connection);
Command.CommandType = CommandType.StoredProcedure;
if (ParameterNames != null)
{
for (int i = 0; i < ParameterNames.Count; i++)
{
SqlParameter Parameter = new SqlParameter(ParameterNames[i], ParameterValues[i]);
if (Parameter.SqlDbType.Equals(SqlDbType.NVarChar))
{
Parameter.SqlDbType = SqlDbType.VarChar;
}
if (Parameter.SqlValue == null)
{
Parameter.SqlValue = DBNull.Value;
}
Command.Parameters.Add(Parameter);
}
}
Reader = Command.ExecuteReader();
SPResult = new DataTable();
SPResult.Load(Reader);
}
catch (Exception ex)
{
throw;
}
finally
{
Connection.Close();
if (Reader != null)
{
Reader.Close();
}
}
return SPResult;
}
I would like to know if there is a straight-forward way to convert this DataTable into a Model that can then be passed to a View (like, for example, the model binding that happens in an AJAX post) and, if there isn't, what are the alternatives. I know that using LINQ would probably solve this problem, but I can't use it.
Thanks in advance.
Best regards.

Found a solution.
I built a generic method that translates any DataTable into a List of whatever class I specify:
public static List<T> Translate<T>(DataTable SPResult, Func<object[],T> del)
{
List<T> GenericList = new List<T>();
foreach (DataRow Row in SPResult.Rows)
{
GenericList.Add(del(Row.ItemArray));
}
return GenericList;
}
where del is a delegate. When calling this method, del should be the constructor of the specified class. Then, in all Model classes, I built a constructor that receives an object[] RowFromTable
public class MyClass
{
public int ID { get; set; }
public string Description { get; set; }
public FormaProcesso(object[] RowFromTable)
{
this.ID = (int)RowFromTable[0];
this.Description = RowFromTable[1].ToString();
}
}
Finally, to put it all together, this is what happens when I call the Web Method:
public List<MyClass> GetAll()
{
DataTable SPResult = MyWebService.GetAll().Table;
return Translate<MyClass>(SPResult, l => new MyClass(l));
}
Got the idea from here

Related

Database handler globally as Singleton pattern in xamarin forms

I am developing an application which have a local database for offline support. So I am using Sqlite.net.pcl plugin and its working fine for all Create, Insert, Update and Delete table for every class model.
But instead of creating a separate database activities like insert, get, update for each Model class, I tried to worked on singeton pattern of common database handler(DatabasHandler.cs).
This is my code which I tried to workout singleton pattern,
public void CreateTable<T>() where T : new()
{
var myClass = new T();
myDatabase.CreateTableAsync<T>().Wait();
}
I called this function from my EmployeeViewModel class like this;
App.Database.CreateTable<EmployeeModel>();
here EmployeeModel is a model class and its worked fine, also the above function is successfully created a Employee Table. Doing the same way I created rest of the Tables from each ViewModel like this;
App.Database.CreateTable<SalaryModel>(); // call from SalaryViewModel Page
App.Database.CreateTable<EmployeeAttendanceModel>(); // call from AttendanceViewModel Page
Next: So how can I insert and get all list items into DatabaseHandler.cs using same (Create Table)singleton pattern. My question is;
How should I create a method for Insert/Get/Update a list in DatabaseHandler.cs(Singleton class)?
How should I call those method(Insert/Get/Update) from its viewmodel?
Please help me,
Now I had a similar thing in my Old XF app this is how I implemented the Singleton this will also answer your first question:
How should I create a method for Insert/Get/Update a list in DatabaseHandler.cs(Singleton class)?
public class DatabaseHandler: IDisposable
{
private SQLiteConnection conn;
//public static string sqlpath;
private bool disposed = false;
private static readonly Lazy<DatabaseHandler> database = new Lazy<DatabaseHandler>(() => new DatabaseHandler());
private DatabaseHandler() { }
public static DatabaseHandler Database
{
get
{
return database.Value;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
Dispose();
}
disposed = true;
}
public bool InitDatabase()
{
var ifExist = true;
try
{
this.CreateDatabase();
ifExist = TableExists(nameof(LocationModel), conn);
if (!ifExist)
this.CreateTable<LocationModel>();
return true;
}
catch (Exception ex)
{
return false;
}
}
public static bool TableExists(String tableName, SQLiteConnection connection)
{
var cmd = connection.CreateCommand("SELECT name FROM sqlite_master WHERE type = 'table' AND name = #name", new object[] { tableName });
//cmd.CommandText = "SELECT * FROM sqlite_master WHERE type = 'table' AND name = #name";
//cmd.Parameters.Add("#name", DbType.String).Value = tableName;
string tabledata = cmd.ExecuteScalar<string>();
return (cmd.ExecuteScalar<string>() != null);
}
public SQLiteConnection GetConnection()
{
var sqliteFilename = "xamdblocal.db3";
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
Console.WriteLine(path);
if (!File.Exists(path)) File.Create(path);
//var plat = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid();
var conn = new SQLiteConnection(path);
// Return the database connection
return conn;
}
private bool CreateDatabase()
{
conn = GetConnection();
string str = conn.DatabasePath;
return true;
}
public bool CreateTable<T>()
where T : new()
{
conn.DropTable<T>();
conn.CreateTable<T>();
return true;
}
public bool InsertIntoTable<T>(T LoginData)
where T : new()
{
conn.Insert(LoginData);
return true;
}
public bool InsertBulkIntoTable<T>(IList<T> LoginData)
where T : class //new()
{
conn.InsertAll(LoginData);
return true;
}
public List<T> SelectDataFromTable<T>()
where T : new()
{
try
{
return conn.Table<T>().ToList();
}
catch (Exception ex)
{
return null;
}
}
public List<T> SelectTableDatafromQuery<T>(string query)
where T : new()
{
return conn.Query<T>(query, new object[] { })
.ToList();
}
public bool UpdateTableData<T>(string query)
where T : new()
{
conn.Query<T>(query);
return true;
}
public void UpdateTableData<T>(IEnumerable<T> query)
where T : new()
{
conn.UpdateAll(query);
}
public void UpdateTableData<T>(T query)
where T : new()
{
conn.Update(query);
}
public bool DeleteTableData<T>(T LoginData)
{
conn.Delete(LoginData);
return true;
}
public bool DeleteTableDataFromPrimaryKey<T>(object primaryKey)
{
conn.Delete(primaryKey);
return true;
}
public bool DeleteTableDataFromQuery<T>(string query)
where T : new()
{
conn.Query<T>(query);
return true;
}
}
How should I call those method(Insert/Get/Update) from its viewmodel? Please help me,
Now for Eg: you want to insert location's Lat Long in your local database where your local model looks something like this:
public class LocationModel
{
[AutoIncrement, PrimaryKey]
public int Id { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public string Address { get; set; }
}
So first what you will do is create an instance of LocationModel something like this:
var locationModel = new LocationModel
{
Latitude = location.Latitude,
Longitude = location.Longitude
};
Then insert it something like this:
DatabaseHandler.Database.InsertIntoTable<LocationModel>(locationModel);
Also, do not forget to add the SQLiteNetExtensions in your project for Linq support.
Goodluck feel free to revert in case of queries

Insertion operation in SqlCe in windows phone

I am trying to insert some data into mydatabase but getting error like "Can't perform Create, Update, or Delete operations on 'Table(Dic)' because it has no primary key."
My database name is "condrokotha_new.sdf" and it has a table named "dic" which have 2 columns named "english" and "bangla". I made this database in another C# project in vs 2010. Then i used this database into my windowsphone project. I can show data from database but when i try to insert data i am getting error.
Here is my code:
public partial class MainPage : PhoneApplicationPage
{
condrokotha_newContext db = null;
// Constructor
public MainPage()
{
InitializeComponent();
db = new condrokotha_newContext(condrokotha_newContext.ConnectionString);
db.CreateIfNotExists();
db.LogDebug = true;
}
private void fav_Click(object sender, RoutedEventArgs e)
{
add_new_words("cintakhela","ami");
}
private void add_new_words(string e_word,string b_word)
{
using (condrokotha_newContext context = new condrokotha_newContext(condrokotha_newContext.ConnectionString))
{
Dic d = new Dic();
d.English = e_word;
d.Bangla = b_word;
context.Dics.InsertOnSubmit(d);
context.SubmitChanges();
}
}
}
My data context code like these :
public static string ConnectionString = "Data Source=isostore:/condrokotha_new.sdf";
public static string ConnectionStringReadOnly = "Data Source=appdata:/condrokotha_new.sdf;File Mode=Read Only;";
public static string FileName = "condrokotha_new.sdf";
public condrokotha_newContext(string connectionString) : base(connectionString)
{
OnCreated();
}
#region Extensibility Method Definitions
partial void OnCreated();
#endregion
public System.Data.Linq.Table<Dic> Dics
{
get
{
return this.GetTable<Dic>();
}
}
}
[global::System.Data.Linq.Mapping.TableAttribute(Name="dic")]
public partial class Dic
{
private string _English;
private string _Bangla;
public Dic()
{
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Name="english", Storage="_English", DbType="NVarChar(1000)")]
public string English
{
get
{
return this._English;
}
set
{
if ((this._English != value))
{
this._English = value;
}
}
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Name="bangla", Storage="_Bangla", DbType="NText", UpdateCheck=UpdateCheck.Never)]
public string Bangla
{
get
{
return this._Bangla;
}
set
{
if ((this._Bangla != value))
{
this._Bangla = value;
}
}
}
}
`
How can i insert my data into my database??
Is there anyone who can help in this??
For example you have this
SampleDataContextDataContext db = new SampleDataContextDataContext();
Employee emp = new Employee() {
FirstName = "Experts",
Lastname = "Comment",
Address = "rs.emenu#gmail.com"
}
db.Employees.InsertOnSubmit(emp);
db.SubmitChanges();
The above code will give you same error when u try to insert a new row. The reason is that LINQ does not provide the facility to insert data into a table without a primary key. At this point you have two options.
1.Create a store procedure and call it from LINQ.
SampleDataContextDataContext db = new SampleDataContextDataContext();
db.InsertEmployeeData("Experts","Comment", "rs.emenu#gmail.com");
Here InsertEmployeeData is a a stored procedure, and called it from the code.
2.Create an insert statement and execute using LINQ.
SampleDataContextDataContext db = new SampleDataContextDataContext();
string insertStatement = "Insert into Employee values('Experts', 'Comment','rs.emenu#gmail.com')";
db.ExecuteQuery<Employee>(insertStatement);
Here insert query is normal sql query and executed using the the LINQ ExecuteQuery method.

Trying to call code in my controller but getting Null Reference error

Don't want to over-complicate the issue, but I think I need to post all the code that's hooked into this error.
Using MvcMailer and introduced a separate Send mechanism (for use with Orchard CMS' own EMail).
The MvcMailer Code:
1) AskUsMailer.cs:
public class AskUsMailer : MailerBase, IAskUsMailer
{
public AskUsMailer()
: base()
{
//MasterName = "_Layout";
}
public virtual MvcMailMessage EMailAskUs(AskUsViewModel model)
{
var mailMessage = new MvcMailMessage { Subject = "Ask Us" };
ViewData.Model = model;
this.PopulateBody(mailMessage, viewName: "EMailAskUs");
return mailMessage;
}
}
2) IAskUsMailer.cs:
public interface IAskUsMailer : IDependency
{
MvcMailMessage EMailAskUs(AskUsViewModel model);
}
3) AskUsController.cs: (GETTING NULL REFERENCE ERROR BELOW)
[Themed]
public ActionResult Submitted()
{
//This is the new call (see new code below):
//Note: Debugging steps through eMailMessagingService,
//then shows the null reference error when continuing to
//SendAskUs
eMailMessagingService.SendAskUs(askUsData);
//Below is normal MvcMailer call:
//AskUsMailer.EMailAskUs(askUsData).Send();
return View(askUsData);
}
Note: askUsData is defined in a separate block in the controller:
private AskUsViewModel askUsData;
protected override void OnActionExecuting(ActionExecutingContext
filterContext)
{
var serialized = Request.Form["askUsData"];
if (serialized != null) //Form was posted containing serialized data
{
askUsData = (AskUsViewModel)new MvcSerializer().
Deserialize(serialized, SerializationMode.Signed);
TryUpdateModel(askUsData);
}
else
askUsData = (AskUsViewModel)TempData["askUsData"] ??
new AskUsViewModel();
TempData.Keep();
}
protected override void OnResultExecuted(ResultExecutedContext
filterContext)
{
if (filterContext.Result is RedirectToRouteResult)
TempData["askUsData"] = askUsData;
}
I did not know how to get my EMailMessagingService.cs (see below) call into the controller, so in a separate block in the controller I did this:
private IEMailMessagingService eMailMessagingService;
public AskUsController(IEMailMessagingService eMailMessagingService)
{
this.eMailMessagingService = eMailMessagingService;
}
I think this is part of my problem.
Now, the new code trying to hook into Orchard's EMail:
1) EMailMessagingServices.cs:
public class EMailMessagingService : IMessageManager
{
private IAskUsMailer askUsMailer;
private IOrchardServices orchardServices;
public EMailMessagingService(IAskUsMailer askUsMailer,
IOrchardServices orchardServices)
{
this.orchardServices = orchardServices;
this.askUsMailer = askUsMailer;
this.Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void SendAskUs(AskUsViewModel model)
{
var messageAskUs = this.askUsMailer.EMailAskUs(model);
messageAskUs.To.Add("email#email.com");
//Don't need the following (setting up e-mails to send a copy anyway)
//messageAskUs.Bcc.Add(AdminEmail);
//messageAskUs.Subject = "blabla";
Send(messageAskUs);
}
....
}
The EMailMessagingService.cs also contains the Send method:
private void Send(MailMessage messageAskUs)
{
var smtpSettings = orchardServices.WorkContext.
CurrentSite.As<SmtpSettingsPart>();
// can't process emails if the Smtp settings have not yet been set
if (smtpSettings == null || !smtpSettings.IsValid())
{
Logger.Error("The SMTP Settings have not been set up.");
return;
}
using (var smtpClient = new SmtpClient(smtpSettings.Host,
smtpSettings.Port))
{
smtpClient.UseDefaultCredentials =
!smtpSettings.RequireCredentials;
if (!smtpClient.UseDefaultCredentials &&
!String.IsNullOrWhiteSpace(smtpSettings.UserName))
{
smtpClient.Credentials = new NetworkCredential
(smtpSettings.UserName, smtpSettings.Password);
}
if (messageAskUs.To.Count == 0)
{
Logger.Error("Recipient is missing an email address");
return;
}
smtpClient.EnableSsl = smtpSettings.EnableSsl;
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
messageAskUs.From = new MailAddress(smtpSettings.Address);
messageAskUs.IsBodyHtml = messageAskUs.Body != null &&
messageAskUs.Body.Contains("<") &&
messageAskUs.Body.Contains(">");
try
{
smtpClient.Send(messageAskUs);
Logger.Debug("Message sent to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
catch (Exception e)
{
Logger.Error(e, "An unexpected error while sending
a message to {0} with subject: {1}",
messageAskUs.To[0].Address, messageAskUs.Subject);
}
}
}
Now, in EMailMessagingService.cs I was getting an error that things weren't being implemented, so I auto-generated the following (don't know if this is part of my error):
public void Send(Orchard.ContentManagement.Records.ContentItemRecord recipient, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Records.ContentItemRecord> recipients, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public void Send(System.Collections.Generic.IEnumerable<string> recipientAddresses, string type, string service, System.Collections.Generic.Dictionary<string, string> properties = null)
{
throw new NotImplementedException();
}
public bool HasChannels()
{
throw new NotImplementedException();
}
public System.Collections.Generic.IEnumerable<string> GetAvailableChannelServices()
{
throw new NotImplementedException();
}
2) IEMailMessagingServices.cs
public interface IEMailMessagingService
{
MailMessage SendAskUs(AskUsViewModel model);
}
MvcMailer works fine without this addition (outside of Orchard), but I am trying to get everything working within Orchard.
I just cannot figure out what I am doing wrong. Any thoughts?
Sorry for excessive code.
IEmailMessaginService does not implement IDependency, so it can't be found by Orchard as a dependency. That's why it's null.

windows phone 7 IsolatedStorageSettings.ApplicationSettings complex data

Just a quick question. In WP7, is it really bad design/idea to store complex data using IsolatedStorageSettings.ApplicationSettings? I want to save a collection of some class objects. The properties are marked with [DataMember] attributes.
An example of a class would be,
[DataContract]
public class OfflineItem
{
[DataMember]
public string Id { get; set; }
[DataMember]
public MyItem Item { get; set; }
[DataMember]
public Dictionary<string, string> KeyValues { get; set; }
}
Collection<OfflineItems> offlineItems = new Collection<OfflineItems>();
.....
IsolatedStorageSettings.ApplicationSettings["AllOfflineItems"] = offlineItems;
I tried it and it worked, but I want to know if it is a correct approach and will there be any performance hit in the long run?
#Jonna. I deliberated over this one too. I ended up using/adapating the following generic methods to serialize and deserialize using a IsolatedStorageFile as below. It includes deleting a file if it already exists as you are trying to update the data.
internal static void Write<T>(T obj, string fileName)
{
XmlWriterSettings writerSettings = new XmlWriterSettings
{
Indent = true,
IndentChars = "\t"
};
try
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isoStore.FileExists(fileName))
{
isoStore.DeleteFile(fileName);
}
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Create, isoStore))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (XmlWriter xmlWriter = XmlWriter.Create(isoStream, writerSettings))
{
serializer.Serialize(xmlWriter, obj);
}
}
}
}
catch (IsolatedStorageException ex)
{
Debug.WriteLine(ex.Message);
}
catch (Exception emAll)
{
Debug.WriteLine(emAll.Message);
}
}
internal static T Read<T>(string fileName)
{
try
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Open, isoStore))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(isoStream);
}
}
}
catch (IsolatedStorageException ex)
{
Debug.WriteLine(ex.Message);
throw;
}
catch (Exception emAll)
{
Debug.WriteLine(emAll.Message);
throw;
}
}
Serialization would be called thus:
Serialization.Write<user>(userDetails, App.USERDETAILS);
And deserialization would be called thus:
Items = Serialization.Read<measurements>(App.MEASUREMENTS);
user is a class and userDetails is an object based on the that class. Measurements is a class and Items is an object based on that class. App.USERDETAILS & App.MEASUREMENTS are global strings that contain file names.
Some debug lines have been left in just so progress can be tracked.
It might also be worth considering using SQL + LINQ if you are thinking of migrating to Mango and much of this could be taken care of there...
I would serialize my data (either XML or Binary) to a separate file in IsolatedStorage. Because if IsolatedStorageSettings.ApplicationSettings is overcrowded it will take longer to load any of individual settings.
Here is a general purpose method to serialize your object to xml
public static string SerializeXml(object objectToSerialize)
{
using (var ms = new MemoryStream())
{
var serializer = new XmlSerializer(objectToSerialize.GetType());
serializer.Serialize(ms, objectToSerialize);
ms.Position = 0;
using (var reader = new StreamReader(ms))
{
return reader.ReadToEnd();
}
}
}

Is it possible to return IEnumerable of anonymous objects from DataContext.ExecuteQuery?

I develop a reporting engine where reports are based on templates. Every template has string with SQL query and every report has specific values for SQL query parameters. To render a report I set parameters and call DataContext.ExecuteQuery method to get list of records. But to catch returned columns I have to know their names and have a class with corresponding properties.
Is it possible somehow to return IEnumerable of anonymous objects from DataContext.ExecuteQuery and then determine their properties using Reflection?
I need a LINQ equivalent for SqlDataReader.GetValues.
Thanks!
Until we have C# 4.0 with dynamiс keyword we can use this solution (slightly modified code from an article Executing arbitrary queries in LINQ to SQL by Octavio Hernández Leal):
public static class DataContextExtension
{
public static IEnumerable<Dictionary<string, object>> ExecuteQuery(this DataContext dataContext, string query)
{
using (DbCommand command = dataContext.Connection.CreateCommand())
{
command.CommandText = query;
dataContext.Connection.Open();
using (DbDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
dictionary.Add(reader.GetName(i), reader.GetValue(i));
yield return dictionary;
}
}
}
}
}
This extension method returns IEnumerable of Dictionary<> objects where keys are names of query columns.
Yes, you can do it.
Please have a look at this snippet.
class Program {
static void Main(string[] args) {
var persons = new Person[]{
new Person{Age=22,Name="John Doe",Id=1},
new Person{Age=23,Name="Jack Smith", Id=2},
new Person{Age=34,Name="Sara Parker", Id=3}
};
var anonData = GetAnonTypes(persons);
foreach (var item in anonData as IEnumerable) {
//use reflection to access propties
}
}
static object GetAnonTypes(IEnumerable<Person> persons) {
var query=from p in persons select new{
Id=p.Id,
Name=p.Name
};
return query;
}
}
public class Person {
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}

Resources